awkを使用して変更を適切に保存する


135

私は学習していてawk、変更をファイルに保存sedする-iオプションを使用する場合と同様に、変更をファイルに書き込むオプションがあるかどうかを知りたいです。

リダイレクトを使用して変更を書き込むことができることは理解しています。しかし、それawkを行うためのオプションはありますか?


「リダイレクトを使用してファイルをインプレイス編集する」ためのより一般的な回答については、serverfault.com / a / 547331/313521も参照してください。
ワイルドカード2015年

@ワイルドカード。そこでの解決策はひどく壊れやすいものです。イベントの順序は保証されていません。そのソリューションを使用すると、データが切り捨てられる可能性があります。余談ですが、そのサイトには50人の担当者がいるため、直接コメントすることはできません。SOがなぜUnix / Linuxとサーバー管理に分割されたのか、私には理解できません IMO、それは間違いでした。
ウィリアムパーセル

@WilliamPursell、「イベントの順序は保証されません」—これは実際には誤りです。ソリューションの唯一の脆弱性は、コンテンツの長さがコマンドの最大長より大きい場合です。ただし、イベントの順序は保証されています。
ワイルドカード

@ワイルドカードその注文を保証する標準は何ですか?
ウィリアムパーセル

@WilliamPursell bashのドキュメントで保証されています。他のシェルについては知りません。(ちなみに、あなたのアカウントをリンクすると、100人の担当者アソシエーションボーナスがあり、コメントすることができます。)
ワイルドカード

回答:


142

最新のGNU Awk(4.1.0リリース以降)では、ファイル「インプレース」編集するオプションがあります。

[...]新しい機能を使用して構築された「インプレース」拡張は、GNU「sed -i」機能をシミュレートするために使用できます。[...]

使用例:

$ gawk -i inplace '{ gsub(/foo/, "bar") }; { print }' file1 file2 file3

バックアップを保持するには:

$ gawk -i inplace -v INPLACE_SUFFIX=.bak '{ gsub(/foo/, "bar") }
> { print }' file1 file2 file3

1
@sudo_O-「インプレース」デモンストレーションをありがとう。あなたの答えに賛成しました!
2013年

オプションが削除された可能性がありますか?4.1.3では、「
Keith Hughitt

1
@キース私は同じ質問がありました。試してみたところ、4.1.3で動作しました。 inplaceは実際にはiiSeymourの回答gawkに従って含まれているライブラリなので、として含めることができるものです。inplaceincludefile
cxw 2016年

ここでの重要な警告: 'seen'配列は、コマンドに含まれるすべてのファイルからの重複行でいっぱいになります。したがって、各ファイルにたとえば共通のヘッダーがある場合、最初のファイルの後にすべてのファイルで削除されます。代わりに、各ファイルを個別に扱いたい場合は、*。txtのfのようにする必要があります。do gawk -i inplace '!seen [$ 0] ++' "$ f"; 完了
Nick K9

136

GNU awk 4.1.0以降でない限り...

sedの-iオプションのようなオプションはないので、代わりに次のようにします。

$ awk '{print $0}' file > tmp && mv tmp file

注:これ-iは魔法ではなく、一時ファイルを作成するsedだけで処理されます。


GNU awk 4.1.0以降...

GNU awkこの機能はバージョン4.1.0 (2013年10月5日リリース)に追加されました。これは-i、リリースノートに記載されているオプションを提供するだけの簡単なものではありません。

新しい-iオプション(xgawkから)は、awkライブラリファイルのロードに使用されます。これは、最初の非オプション引数がスクリプトとして扱われるという点で-fとは異なります。

バンドルされたinplace.awkインクルードファイルを使用して、次のように拡張機能を適切に呼び出す必要があります。

$ cat file
123 abc
456 def
789 hij

$ gawk -i inplace '{print $1}' file

$ cat file
123
456
789

この変数INPLACE_SUFFIXを使用して、バックアップファイルの拡張子を指定できます。

$ gawk -i inplace -v INPLACE_SUFFIX=.bak '{print $1}' file

$ cat file
123
456
789

$ cat file.bak
123 abc
456 def
789 hij

私はこの機能が追加されましたうれしいですが、電源は、言語の簡潔さから来て、と私には、実装は非常にawkishではありません-i inplaceあまりにも長い8つの文字である

公式単語の取扱説明書へのリンクです。


あなたの「最初の」例はもっと似ているべきではありません:awk '{ gsub(/foo/, "bar" ) } ; { print $0 }' file > tmp.txt && mv -v tmp.txt file
Tony Barganski、2018年

驚いたことに、2019年4月の時点ではまだgawk 4.0.2です。誰にもそのようなことを言わせないでください。そうすればそのようなバージョンが利用可能になります。
John Lunzer

からawk '{print $0}' file | sponge file使用spongeして短いリテmoreutils
brablc

15

@sudo_O正解です。

これは機能しません:

someprocess < file > file

シェルはリダイレクトを実行してから、制御をsomeprocess(redirections渡します。リダイレクトはゼロサイズ(にファイルを切り捨てられますリダイレクト出力)。したがって、何らかのプロセスが起動されてファイルからの読み取りを希望するときまでに、読み取るデータがありません。>


14

機能するほんの少しのハック

echo "$(awk '{awk code}' file)" > file

魅力的な作品!しかし、awkコマンドを変数に保存して、気の利いたトリックで使用することは可能ですか?
アシュラムン

13

代わりの方法はsponge次のとおりです。

awk '{print $0}' your_file | sponge your_file

'{print $0}'awkスクリプトとyour_file、その場で編集するファイルの名前で置き換えます。

sponge 入力を完全に吸収してから、ファイルに保存します。


スポンジはどのように標準/ポータブルですか?
トーマス

2
spongeの一部ですmoreutils。そのため、ほとんどのシステムではデフォルトでは存在しません。しかし、少なくともspongeそれ自体は十分に移植可能で、ほとんどどこでも実行できるように見えます。
MarSoft、

1
teeベースのソリューションと比較したこのソリューションの欠点は、sponge書き出す前にすべてをRAMに読み込むため、大きなファイルでフリーズすることです。
MarSoft

5

フォローできません

echo $(awk '{awk code}' file) > file

これはうまくいくはずです

echo "$(awk '{awk code}' file)" > file

3

一時ファイルを作成せずにversionで使用できるawkのみのソリューションが必要な場合==(gawk 4.1.0):

awk '{a[b++]=$0} END {for(c=0;c<=b;c++)print a[c]>ARGV[1]}' file

4
しかし、これはファイル全体をメモリにバッファリングしますか?20GBのファイルを考えてみましょう。
アミットナイドゥ、2016年

0

Tシャツの使用

 awk '{awk code}' file | tee file

teeコマンドテイク場所と後に実行されるawkコマンドが原因に仕上がっています|


5
これは誤りです。2つのコマンドは並行して実行され、データはパイプを介して直ちにストリーミングされます。バッファ(私のマシンでは8192バイト)より大きいファイルは切り捨てられ、データが失われます。
tripflag
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.