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--includegawk の -i オプションまたは @include ディレクティブを安全に使用するにはどうすればよいでしょうか?これに関連するセキュリティ問題については、下記の Stéphane のコメントを参照してください。GNU で配布されるソース ライブラリの 1 つに、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
  • 出力を一時ファイルにリダイレクトします。
  • 次に、一時ファイルの内容を元のファイルに移動します。

関連情報