Como alterar um arquivo no local usando o awk? (como com "sed -i")

11

Eu tenho um awkscript new.awk:

 BEGIN { FS=OFS="," }
 NR==1 {
for (i=1; i<=NF; i++) {
    f[$i] = i
}
   } 
  NR > 1 {
 begSecs= mktime(gensub(/[":-]/," ","g",$(f["DateTime"])))
 endSecs = begSecs + $(f["TotalDuration"])
 $(f["CallEndTime"]) = strftime("%Y-%m-%d %H:%M:%S", endSecs)
 }
 { print }

Eu estou chamando isso de casca

awk new.awk sample.csv

... mas eu posso ver as mudanças no terminal. Como fazer a alteração no local no arquivo, como ao usar sed -i?

mittu
fonte

Respostas:

16

O GNU awk(normalmente encontrado em sistemas Linux), desde a versão 4.1.0, pode incluir uma " awkbiblioteca de origem" com -iou --includena linha de comando. Uma das bibliotecas de origem que é distribuída com o GNU awké chamada inplace:

$ cat file
hello
there
$ awk -i inplace '/hello/ { print "oh,", $0 }' file
$ cat file
oh, hello

Como você pode ver, isso faz com que a saída do awkcódigo substitua o arquivo de entrada. O ditado de linha therenão é mantido, pois não é produzido pelo programa.

Com um awkscript em um arquivo, você o usaria como

awk -i inplace -f script.awk datafile

Se a awkvariável INPLACE_SUFFIXfor definida como uma sequência, a biblioteca fará um backup do arquivo original com o sufixo do nome do arquivo.

awk -i inplace -v INPLACE_SUFFIX=.bak -f script.awk datafile

Se você tiver vários arquivos de entrada, cada arquivo será editado individualmente no local. Mas você pode desativar a edição no local de um arquivo (ou um conjunto de arquivos) usando inplace=0na linha de comando antes desse arquivo:

awk -i inplace -f script.awk file1 file2 inplace=0 file3 inplace=1 file4

No comando acima, file3não seria editado no local.


Para uma "edição no local" mais portátil de um único arquivo, use

tmpfile=$(mktemp)
cp file "$tmpfile" &&
awk '...some program here...' "$tmpfile" >file
rm "$tmpfile"

Isso copiaria o arquivo de entrada para um local temporário e aplicaria o awkcódigo no arquivo temporário enquanto redirecionava para o nome do arquivo original.

A execução das operações nesta ordem ( awkem execução no arquivo temporário, não no arquivo original) garante que os metadados do arquivo (permissões e propriedade) do arquivo original não sejam modificados.

Kusalananda
fonte
4

Tente isso.

awk  new.awk sample.csv > tmp.csv && mv -f tmp.csv sample.csv
  • redirecione a saída para um arquivo temporário.
  • depois mova o conteúdo do arquivo temporário para o arquivo original.
Siva
fonte
1
Se você olhar para o código-fonte awk no local, é exatamente isso que ele faz: cria um arquivo temporário, redireciona o stdout para lá e, no final, o renomeia para o arquivo de entrada.
chx 23/01/19