如何使用 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 }

我在 shell 中呼叫這個

awk new.awk sample.csv

……但我可以看到終端中的變化。如何在文件中就地進行更改,就像使用時一樣sed -i

答案1

GNU awk(常見於 Linux 系統)從 4.1.0 版開始,可以在命令列中包含一個「來源庫」(請awk參閱-i--include如何安全地使用 gawk 的 -i 選項或 @include 指令?以及下面 Stéphane 對與此相關的安全問題的評論)。與 GNU 一起發布的來源庫之一awkinplace

$ 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
  • 將輸出重定向到暫存檔案。
  • 然後將臨時文件的內容移到原始文件。

相關內容