出力をリダイレクトすると、時々空のファイルが生成されるのはなぜですか? [コピー]

出力をリダイレクトすると、時々空のファイルが生成されるのはなぜですか? [コピー]

シェルパイプラインはあまりにも強力で、時には残念です。

はい

同じたとえば、パイプ

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削除するより良い方法を知っていますが、ここで気になるのはシェルの構文を徹底的に学ぶことです。echocatgrepこの質問は、上記の特定の問題を解決する方法に関するものではありません。

Q1(編集者:トピック以外)文法を学ぶときに使用できる良い資料はありますか?

シェルごとに構文が異なる場合があるので心配です。

第2四半期シェルを冗長にしてコマンドを実行するたびに、シェルが何をしているのかを正確に確認できますか?

Q3(編集:トピックから抜け出す)ベストプラクティスのための他の提案はありますか?ありがとうございます!

答え1

考える3.1.1 シェル動作、特に操作が実行される順序は次のとおりです。

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

これは、cat file > file出力リダイレクト(ファイル切り捨て)がcatビルド前に発生し、cat作業する空のファイルがあることを意味します。

しかしecho "$(cat file)" > file予想したようにコマンドの置き換えシェル拡張、これはリダイレクト前に発生します。

典型的なアドバイスは

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

答え2

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

A1:シェル構文を学ぶための良いリソースは次のとおりです。Bash スクリプトのための絶対ガイド、国際海事機関

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

A3:[solved]クエリに追加してください。既に知っている問題ではなく、問題に対する解決策を見つけてください。

答え3

問題を解決する1つの方法は、順次リダイレクト、拡張、サブシェルなどが何が起こるのかを正確に理解して、これらのエラーが発生する前にキャッチできるようにすることです。

私はこれをお勧めしません。時にはまだ混乱してデータが失われる可能性があります。

楽しむいいえこれらすべてを正しく維持し、より愚かなコードを書く能力を信じてください。 私たちは皆時々愚かです。

だから

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

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

追加の利点として、その他まったく実行しないでください。このスクリプトを実行するとエラーが発生します。

このアプローチのコストは、.oldファイルがどこにでもあるということです。必要な日にお支払いいただき、喜ぶプレミアムです。皿は非常に安いです。

関連情報