最初のコマンドが失敗した場合にBashパイプラインで2番目のコマンドが開始されないようにする

最初のコマンドが失敗した場合にBashパイプラインで2番目のコマンドが開始されないようにする

パイプに関するいくつかの有用な議論を(やや)学んだ後、例えば 終了状態を別のプロセスにパイプにインポートするそしてパイプラインの1つのプロセスが失敗した場合は終了します。最初のコマンドが失敗した場合でも、2番目のコマンドを開始することは避けられません。配管の必要な詳細を見逃していますか?

例えば

$ somecommand | tar -T - -czf /tmp/someProject.tar.gz

tar.gz正しく機能せず、予想されるファイルのリストの代わりにいくつかのエラーメッセージのみを生成する場合は、ほとんど空のsomecommandファイルを生成しないでください。

答え1

はい、そこに配管に関するいくつかの基本的な詳細があります。

パイプラインのポイントは、複数のコマンドを並列に実行することです。これにより、すべてのデータを完全に保存する必要がなく、すべてのプロセスが同時に動作できるため、時間が節約されます。定義によれば、第1の命令が終了する前に第2の命令が開始されるので、第1の命令の終了状態がまだ使用できないことを意味する。

簡単な解決策は一時ファイルを使用することです。データ自体ではなくファイル名のリストだけを渡すため、ここではリポジトリは大きな問題ではありません。たとえば、

tmp=$(mktemp)
if somecommand > "$tmp"; then
    tar -T - -czf /tmp/someProject.tar.gz < "$tmp"
fi
rm -f "$tmp"

または、実際にterdonが述べたようにtartarファイルを実行し、失敗した場合は削除します。somecommandただし、somecommand失敗する前に部分的で重要なファイルのリストを作成すると、削除するアーカイブを作成するときに不要なI / Oが発生する可能性があります。

また、少なくともGNU tarには-Tコマンドラインオプションのように見える引用符と行をデフォルトで処理する機能があるので、不快なファイル名がある場合はこれを考慮するか検討することをお勧めします--verbatim-files-from--null他のtar実装にも同様の問題がある可能性があります。 。

答え2

パイプ命令の性格を誤解したようです。

コマンドパイプラインからみんな並列で開始するコマンド(参照ここ例えば)。これは、実行中に生成された出力が読み取られるため、設定がtar正常に完了するまで「待機」できない理由です。somecommandtarsomecommand

この状況を軽減するために採用できるいくつかの解決策があります。

  • 出力をsomecommand一時ファイルにバッファリングし、終了ステータスtar信号somecommandが「成功」の場合にのみ実行してから削除します(保存スペースが十分な場合にのみ可能です)。
  • @terdonが述べたように失敗した場合は、このpipefailオプションを使用して使用できないファイルを削除してください。tar.gzsomecommand

答え3

最も簡単な方法はを使用することです&&。出力もキャプチャしたいので、まずリダイレクトしてから使用できます。

somecommand > somefile && tar -T somefile -czf /tmp/someProject.tar.gz

thensomecommand以外のもので終了すると、実行は発生しません。exit 0tar

答え4

パイプはこれを行う方法ではありません。この設定は、最初のコマンドが成功した場合にのみ&&2番目のコマンドを実行します。

たとえば、「goober」というファイルがないディレクトリの場合:

$ ls goober | echo "done"
done
ls: cannot access 'goober': No such file or directory
$ ls goober && echo "done"
ls: cannot access 'goober': No such file or directory

あなたの例では:

$ somecommand && tar -T - -czf /tmp/someProject.tar.gz

somecommand失敗するとtar実行されません。

関連情報