Как изменить файл на месте с помощью awk? (как с «сед-я»)

11

У меня есть awkсценарий 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 }

Я называю это в оболочке

awk new.awk sample.csv

... но я вижу изменения в терминале. Как сделать изменение на месте в файле, как при использовании sed -i?

mittu
источник

Ответы:

16

GNU awk(обычно используется в системах Linux), начиная с версии 4.1.0, может включать « awkисходную библиотеку» с командной строкой -iили --includeв командной строке. Одна из исходных библиотек, которая распространяется с GNU, awkназывается inplace:

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

Как видите, это приводит к тому, что вывод awkкода заменяет входной файл. Поговорка thereне сохраняется, так как она не выводится программой.

Со awkскриптом в файле, вы бы использовали его как

awk -i inplace -f script.awk datafile

Если для awkпеременной INPLACE_SUFFIXзадана строка, библиотека создаст резервную копию исходного файла с суффиксом имени файла.

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

Если у вас есть несколько входных файлов, то каждый файл будет редактироваться отдельно. Но вы можете отключить редактирование на месте для файла (или набора файлов), используя inplace=0в командной строке перед этим файлом:

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

В приведенной выше команде file3не будет редактироваться на месте.


Для более переносимого «редактирования на месте» одного файла используйте

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

Это позволит скопировать входной файл awkво временную папку, а затем применить код к временному файлу при перенаправлении на исходное имя файла.

Выполнение операций в указанном порядке (выполнение awkнад временным файлом, а не над исходным файлом) гарантирует, что метаданные файла (права доступа и владение) исходного файла не изменятся.

Кусалананда
источник
4

Попробуй это.

awk  new.awk sample.csv > tmp.csv && mv -f tmp.csv sample.csv
  • перенаправить вывод во временный файл.
  • затем переместите содержимое временного файла в исходный файл.
Сива
источник
1
Если вы посмотрите на исходный код awk inplace, это именно то, что он делает: создает временный файл, перенаправляет туда стандартный вывод и в конце переименовывает его во входной файл.
chx