web-dev-qa-db-ja.com

出力をリダイレクトすると空のファイルが生成されることがあるのはなぜですか?

シェルパイプラインの能力は非常に優れているため、失敗することがあります。

ちょうどとしての例、パイプライン

echo abc > file.txt
cat file.txt | sed 's/a/1/' > file.txt

空のfile.txtをくれます。シェルがおそらく最初に>を呼び出すことに気づき、変更を加えました。

echo abc > file.txt
{cat file.txt | sed 's/a/1/'} > file.txt

もう一度、別の空のファイルfile.txtに驚かされます。最終的に機能する醜い方法は

echo abc > file.txt
echo $(cat file.txt | sed 's/a/1') > file.txt

これにより、シェルは最初にサブシェルを実行し、次にリダイレクトします。

質問

私はsedechocat ..などを取り除くことができるgrepのより良い習慣を知っていますが、私は何ですかここで気になるのは、シェルの文法を完全に学ぶことです。 この質問は、上記の特定の問題を修正する方法に関するものではありません。

Q1(編集:オフトピック)文法を学ぶのに役立つリソースはありますか?

シェルによって文法が異なる可能性があるため、

Q2 Shellを冗長にして、コマンドを実行するたびに、シェルが何をしているかを明確に確認できますか?

Q3(編集:トピック外)グッドプラクティスに関するその他のアドバイスはありますか?ありがとうございました!

4
Student

してはいけないことの1つを見つけました:-)作業中のファイルにリダイレクトしないでください!

A1:シェルの文法を学ぶための良いリソースは 絶対bashスクリプトガイド 、IMOです

A2:bashスクリプトの場合、set +xを使用してより詳細な出力を得ることができますが、「プロンプトでの実行」レベ​​ルで同じことを行う方法がわかりません。

A3:[solved]を検索キーワードに追加します。すでに知っている問題の詳細ではなく、問題の解決策を見つけます。

4
markgraf

.1.1シェル操作 を検討してください。特に、実行される順序は次のとおりです。

  • リダイレクトはbeforeの前に処理され、実際にコマンドが実行されますが、
  • 拡張はリダイレクトの前に処理されます。

つまり、_cat file > file_の場合、catが生成される前に出力のリダイレクト(ファイルが切り捨てられます)が発生し、catで空のファイルを操作できるようになります。

しかしecho "$(cat file)" > fileCommand SubstitutionShell Expansion であり、リダイレクトの前に発生するため、期待どおりの動作をします。

典型的なアドバイスは

_cat file > tmpfile && mv tmpfile file
_

ここでは mktemp を使用できます。

または、moreutilsパッケージをインストールして sponge を使用します

_cat file | sponge file
_

使用している特定のコマンドに対処するために、

_cat file.txt | sed 's/a/1/' > file.txt
_

(GNU sed)と仮定して)

_sed -i 's/a/1/' file.txt
_
10
glenn jackman

問題を解決する1つの方法は、発生する前にこのタイプのエラーをキャッチできるように、リダイレクト、展開、サブシェルなどが発生する順序を正確に学習することです。

これはお勧めしません。あなたはまだ時々台無しになり、コストはデータを失う可能性があります。

これらすべてを真っ直ぐに保ち、ばか証明コードを書く能力は信頼できないではない方が良いです。 私達は時々バカです。

そう

cp file.txt file.txt.old
cat file.txt.old | sed 's/a/1/' > file.txt

これは、行1が行2の前に発生することを除いて、イベントの順序に依存しないという点でより単純です。

追加の利点として、このスクリプトをまったく実行してはならないときにotherエラーから保護します。

このプラクティスのコストは、あなたが.oldファイルはどこにでもあります。これは、あなたがそれを必要とする日に支払ったことがうれしい保険料です。ディスクは安いです。

0
Stig Hemmer