シェルパイプラインの能力は非常に優れているため、失敗することがあります。
ちょうどとしての例、パイプライン
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
これにより、シェルは最初にサブシェルを実行し、次にリダイレクトします。
私はsed
、echo
、cat
..などを取り除くことができるgrep
のより良い習慣を知っていますが、私は何ですかここで気になるのは、シェルの文法を完全に学ぶことです。 この質問は、上記の特定の問題を修正する方法に関するものではありません。
Q1(編集:オフトピック)文法を学ぶのに役立つリソースはありますか?
シェルによって文法が異なる可能性があるため、
Q2 Shellを冗長にして、コマンドを実行するたびに、シェルが何をしているかを明確に確認できますか?
Q3(編集:トピック外)グッドプラクティスに関するその他のアドバイスはありますか?ありがとうございました!
してはいけないことの1つを見つけました:-)作業中のファイルにリダイレクトしないでください!
A1:シェルの文法を学ぶための良いリソースは 絶対bashスクリプトガイド 、IMOです
A2:bashスクリプトの場合、set +x
を使用してより詳細な出力を得ることができますが、「プロンプトでの実行」レベルで同じことを行う方法がわかりません。
A3:[solved]
を検索キーワードに追加します。すでに知っている問題の詳細ではなく、問題の解決策を見つけます。
.1.1シェル操作 を検討してください。特に、実行される順序は次のとおりです。
つまり、_cat file > file
_の場合、cat
が生成される前に出力のリダイレクト(ファイルが切り捨てられます)が発生し、cat
で空のファイルを操作できるようになります。
しかしecho "$(cat file)" > file
は Command Substitution が Shell 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
_
問題を解決する1つの方法は、発生する前にこのタイプのエラーをキャッチできるように、リダイレクト、展開、サブシェルなどが発生する順序を正確に学習することです。
これはお勧めしません。あなたはまだ時々台無しになり、コストはデータを失う可能性があります。
これらすべてを真っ直ぐに保ち、ばか証明コードを書く能力は信頼できないではない方が良いです。 私達は時々バカです。
そう
cp file.txt file.txt.old
cat file.txt.old | sed 's/a/1/' > file.txt
これは、行1が行2の前に発生することを除いて、イベントの順序に依存しないという点でより単純です。
追加の利点として、このスクリプトをまったく実行してはならないときにotherエラーから保護します。
このプラクティスのコストは、あなたが.old
ファイルはどこにでもあります。これは、あなたがそれを必要とする日に支払ったことがうれしい保険料です。ディスクは安いです。