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

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

У меня есть 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?

решение1

GNU awk(обычно встречается в системах Linux), начиная с версии 4.1.0, может включать « awkисходную библиотеку» с помощью командной строки -iили --includeв командной строке (см.Как безопасно использовать опцию gawk -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над временным файлом, а не над исходным файлом) гарантирует, что метаданные исходного файла (разрешения и права собственности) не будут изменены.

решение2

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

awk  new.awk sample.csv > tmp.csv && mv -f tmp.csv sample.csv
  • перенаправить вывод во временный файл.
  • затем переместите содержимое временного файла в исходный файл.

Связанный контент