¿Cómo cambiar un archivo in situ usando awk? (como con "sed -i")

¿Cómo cambiar un archivo in situ usando awk? (como con "sed -i")

Tengo un awkguión 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 }

Estoy llamando a esto en shell

awk new.awk sample.csv

... pero puedo ver los cambios en la terminal. ¿Cómo realizar el cambio in situ en el archivo, como cuando se usa sed -i?

Respuesta1

GNU awk(comúnmente encontrado en sistemas Linux), desde la versión 4.1.0, puede incluir una " awkbiblioteca fuente" con -io --includeen la línea de comando (ver¿Cómo utilizar de forma segura la opción -i de gawk o la directiva @include?junto con el comentario de Stéphane a continuación para cuestiones de seguridad relacionadas con esto). Una de las bibliotecas fuente que se distribuye con GNU awkse llama inplace:

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

Como puede ver, esto hace que la salida del awkcódigo reemplace el archivo de entrada. La línea que dice thereno se mantiene porque el programa no la genera.

Con un awkscript en un archivo, lo usarías como

awk -i inplace -f script.awk datafile

Si la awkvariable INPLACE_SUFFIXse establece en una cadena, entonces la biblioteca haría una copia de seguridad del archivo original con eso como sufijo de nombre de archivo.

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

Si tiene varios archivos de entrada, cada archivo se editará individualmente en el lugar. Pero puedes desactivar la edición in situ para un archivo (o un conjunto de archivos) usando inplace=0la línea de comando antes de ese archivo:

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

En el comando anterior, file3no se editaría en su lugar.


Para una "edición in situ" más portátil de un solo archivo, utilice

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

Esto copiaría el archivo de entrada a una ubicación temporal, luego aplicaría el awkcódigo en el archivo temporal mientras se redirige al nombre del archivo original.

Realizar las operaciones en este orden (ejecutar awken el archivo temporal, no en el archivo original) garantiza que los metadatos del archivo (permisos y propiedad) del archivo original no se modifiquen.

Respuesta2

Prueba esto.

awk  new.awk sample.csv > tmp.csv && mv -f tmp.csv sample.csv
  • redirigir la salida a un archivo temporal.
  • luego mueva el contenido del archivo temporal al archivo original.

información relacionada