特定のパターンに一致する複数のファイルにいくつかのテキストを追加するコマンドを作成しています。
for file in $(find . -name "*.txt"); do sed "1s/^/hello/" $file; done
stdout
別のファイル(たとえば)に書き込むと、すべてが計画"$file.bak"
どおりに進みますが、コマンドを使用して同じファイルに書き換えようとすると、ファイルの内容が消去されます。
for file in $(find . -name "*.txt");do sed "1s/^/hello/" $file > $file; done
私はこの動作が驚くべきことだと思います。なぜこれが起こるのかを概念的に説明できる人はいますか?私は同じ効果bash
でmacOSでこれを試しました。zsh
(私はsed -i ""
正しい場所に書くことを知っていますが、それを書く前に結果を別のコマンドにパイプしたいと思います。)
ベストアンサー1
概念的な驚きはこの声明にあります。
しかし、同じファイルにコマンドを書き換えようとすると
使用すると、書き換えるためにファイルを開くのcmd file > file
ではなくcmd
、シェル自体を開きます。これが見つかったときにシェルが最初にすることは、書き込みモード> file
で場所0でファイルを開き(したがってファイルが切り捨てられ)、stdoutをファイルにリダイレクトすることです。したがってcmd
、読み始める瞬間はfile
すでに空です。
または、より正式には次のようになります。
cmd
Shell は実行する新しいプロセスを分岐します。- 新しいプロセス(まだ実行中のシェルコード)が
file
位置0に書き込むために開きます(したがって切り捨てられます)。 - 新しいプロセスの実行は、
cmd
実際には現在のプロセス内で新しいバイナリを起動します。 cmd
ランタイム標準出力は以下を指します。file
cmd
読むために開いていますfile
が、今は空です。
一方、sed -i '1s/^/hello/' file
別々に管理されたファイルを使用する場合sed
(技術的にはバックグラウンドで一時ファイルを生成します。)