人はそれを考えるかもしれません
echo foo >a
cat a | rev >a
a
にはoof
が含まれます。代わりに空のままにします。
rev
をa
にどのように適用しますか?そのためのアプリがあります! sponge
のmoreutils
コマンドは、まさにこのために設計されています。 Linuxを実行している場合は、すでにインストールされている可能性があります。そうでない場合は、オペレーティングシステムのリポジトリでsponge
またはmoreutils
を検索してください。次に、次のことができます。
echo foo >a
cat a | rev | sponge a
または、 oC を避けます:
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
、強調鉱山から):
スポンジは標準入力を読み取り、それを指定されたファイルに書き込みます。 シェルリダイレクトとは異なり、スポンジはすべての入力を吸収してから出力ファイルを書き込みます。これにより、同じファイルから読み書きするパイプラインを構築できます。
これを修正する別の方法は、切り捨てない書き込みメソッドを使用することです
rev a | dd conv=notrunc of=a
これは次の理由でのみ機能します:
revは出力を生成する前にコンテンツを読み取り、出力はすでに読み取られた量より長くなることはありません
新しいファイルのコンテンツは元のサイズと同じかそれよりも大きい(この場合は同じサイズ)
このアプローチは、一時的なコピーを保持するには大きすぎるファイルのインプレース変更に役立つ場合があります。
_cat a | rev > a
_
なぜ[
a
が空のままになっている]のですか?
上記のパイプラインでは、シェルは2つのサブプロセスを分岐し、パイプラインの2つの部分のそれぞれに1つずつです。次に、これらのサブプロセスは問題のコマンドを実行し、最初にリダイレクトを処理し、次にexec*()
関数の1つを呼び出して外部ユーティリティを起動します。サブプロセスは並行して実行され、それらの間のタイミングの保証はありません。
プロセスの実行はそれほど高速ではないため、通常は、右側のシェルがcat
がファイルを読み取る機会を得る前にリダイレクトを設定することが起こります。出力リダイレクト_> a
_はファイルを切り捨てるので、cat
に読み取るものはなく、rev
はデータを受信せず、データを生成しません。左側のリダイレクトも使用した場合(_cat < a | rev > a
_)、a
は切り捨てられる前に読み取り用に開かれる可能性がありますが、cat
にはまだ時間がありません実際にそれを読む前に。
一方、これは私のシステムで一貫して_a contains: foo
_を出力します:
_echo foo > a; cat < a | tee a > /dev/null ; echo "a contains: $(cat a)"
_
ここでは、ファイルを切り捨てるのはtee
なので、これはexec()
およびcat
がファイルを読み取る時間を持つ可能性が高くなった後に発生します。ただし、ファイルが十分に大きい場合は、読み取り中に途中で切り捨てられる可能性があります。
私はmightとおそらくと言いました、OSが別の方法でプロセスをスケジュールすることを決定した場合。
それ以外の場合、
rev
をa
にどのように適用しますか?
通常の解決策は一時ファイルを使用することです:
_cat a | rev > b && mv b a
_
一時ファイル名が使用可能であることを確認できない限り、既存のファイルを上書きする可能性があるという通常の問題があります。おそらくmktemp
を使用する必要があります:
_f=$(mktemp ./tmp.XXXXXX)
cat a | rev > "$f" && mv "$f" a || rm "$f"
_
または、 sponge
tool を使用することもできます。これにより、出力ファイルを開く前に、取得したすべての入力を読み取ることができます(それ以外の場合は、cat
のようになります)。
_cat a | rev | sponge a
_
あるいは単に
_rev < a | sponge a
_
_sponge > a
_は、元のコマンドが機能しないのと同じ理由で間違いです。
スポンジは moreutils からのものであり、標準的なツールではありません。 別のコマンドにパイプする前にコマンド出力を完全にバッファーしますか?
一部のユーティリティは、同様の機能を自分で実装する場合があります。 _sort -o outputfile
_は、終了後にのみ出力ファイルを開きます。参照 `sed --in-place`のように、ソートはファイルのインプレースソートをサポートしていますか?
VimはExモードで使用できます。
ex -s -c '%!rev' -c x a.txt
%
すべての行を選択!
コマンドを実行x
保存して閉じる