web-dev-qa-db-ja.com

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を使用するように、変更をファイルに永続的にするにはどうすればよいですか。

10
mittu

GNU awk(Linuxシステムで一般的に見られる)は、バージョン4.1.0以降、「awkソースライブラリ」を-iまたは--includeとともにコマンドライン。 GNU awkで配布されるソースライブラリの1つは、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を実行)、元のファイルのファイルメタデータ(権限と所有権)が変更されないことが保証されます。

16
Kusalananda

これを試して。

awk  new.awk sample.csv > tmp.csv && mv -f tmp.csv sample.csv
  • 出力を一時ファイルにリダイレクトします。
  • 次に、一時ファイルの内容を元のファイルに移動します。
4
msp9011