誰かが考えるかもしれない
echo foo >a
cat a | rev >a
a
含まれたままですがoof
空です。
- なぜ?
- また、どのように
rev
適用されますかa
?
答え1
これのためのアプリがあります!sponge
fromコマンドはmoreutils
まさにこれのために設計されています。 Linuxを実行している場合は、すでにインストールされています。そうでない場合は、オペレーティングシステムのリポジトリでsponge
またはを検索してくださいmoreutils
。その後、次のことができます。
echo foo >a
cat a | rev | sponge a
または避けてくださいウルク:
rev a | sponge a
この動作の理由は、コマンドが実行される順序によって異なります。実際に最初> a
に実行され、> file
ファイルを消去します。たとえば、
$ echo "foo" > file
$ cat file
foo
$ > file
$ cat file
$
したがって、実行時にcat a | rev >a
実際に行われることは、> a
最初に実行されてファイルが空になるため、cat a
実行時にファイルがすでに空になっていることです。これがsponge
次のように書かれた理由です(man sponge
、ハイライト内の項目)。
Spongeは標準入力を読み取り、それを指定されたファイルに書き込みます。 シェルリダイレクトとは異なり、スポンジは出力ファイルに書き込む前にすべての入力を吸収します。これにより、同じファイルを読み書きするパイプラインを構築できます。
答え2
- 出力の切り捨てが早く行われるので、catは空のファイルを表示します。
- 最初のファイルを一時ファイルとして構成するか、後で名前を変更する一時ファイルとしてrevの出力を指定します。
答え3
この問題を解決する別の方法は、切り捨てることなく書き込みメソッドを使用することです。
rev a | dd conv=notrunc of=a
これは次の理由でのみ機能します。
rev は出力を生成する前に内容を読み込み、出力は読み取った量より長くありません。
新しいファイルの内容は元のファイルの内容と同じかそれ以上です(この場合はサイズは同じです)。
- ddはファイルを切り捨てずに書き込み用にファイルを開きます。
この方法は、大きすぎて一時コピーを保持できないファイルを内部で変更するのに役立ちます。
答え4
>file
新しい空のファイルを作成するか、既存のファイルを切り捨てます。したがって、ファイルに読み込む内容がありませんrev
。
sponge
他の回答で述べたように、この目的に使用できます。しかし、sponge
誰もが利用できるわけではありません。
シェルに関する一般的な解決策は次のとおりです。
exec 3<file; rm file; rev <&3 >file; exec 3<&-
これにより、ファイル(fd 3など)が開き、削除されます。より正確には、ファイル自体ではなくファイルのディレクトリエントリのみを削除します。ファイルへのすべてのハードリンクが削除され、ファイルへのすべてのハンドルが閉じられるまで、ファイルは削除されません。
次に、rev
「削除されたファイル」で読み取りを実行します。出力は新しいファイルに転送されます。この新しいファイルは元のファイルと同じ名前ですが、別のファイルです。したがって、紛争はありません。
最後に、ソースファイルの記述子を閉じて解放します。
上記のアプローチの問題は、問題が発生するとデータが失われることです。そのため、以下を好むことができます(上記よりも多くのディスク容量を使用しません)。
( rev file >file.new && mv file.new file ) || rm file.new