20

(おそらく、一部のプログラムが入力ファイルのプロセス置換を受け入れないかどうかに関連していますか?

一部のBash単体テストスクリプトでは、次のトリックを使用して、コマンドのstdoutとstderrをログに記録して表示しています。

command > >(tee "${stdoutF}") 2> >(tee "${stderrF}" >&2)

このプロセスはstdoutへの出力を生成するため、$stdoutFファイルはデータを取得します。次に、データを出力しない別のコマンドを実行します。

diff -r "$source" "$target" > >(tee "${stdoutF}") 2> >(tee "${stderrF}" >&2)

ただし、空のテストが実行される前に、このプロセスが常に正常に終了するようには見えません(shunit-ngを使用)。

assertNull 'Unexpected output to stdout' "$(<"$stdoutF")"

100回の実行テストでは、これは25回失敗しました。

syncファイルの空性をテストする前に呼び出すだけで十分な場合:

sync
assertNull 'Unexpected output to stdout' "$(<"$stdoutF")"

...および/またはコマンドのシーケンスを強制することによって機能する必要があります:

diff -r "$source" "$target" \
> >(tee "${stdoutF}"; assertNull 'Unexpected output to stdout' "$(<"$stdoutF")")
2> >(tee "${stderrF}" >&2)

...および/またはファイルの代わりに直接teeそれを行うことは可能ですか?assertNull

更新sync答えではありません-以下のGillesの応答を参照してください。

更新2 : stdout、stderr、およびstdout+stderrを同期的に保存するためにさらに議論が行われました。答えてくれてありがとう!

4

3 に答える 3

30

bashでは、プロセス置換置換コマンドfoo > >(bar)は終了するとすぐにfoo終了します。(これはドキュメントでは説明されていません。)これは次のコマンドで確認できます。

: > >(sleep 1; echo a)

このコマンドはすぐに戻り、a1秒後に非同期で出力します。

あなたの場合、teeコマンドは完了後に完了するのにほんの少しの時間がかかりますcommand。追加することで完了するのに十分な時間がsync与えteeられましたが、これは競合状態を削除するものではなく、追加するsleepだけで、競合が発生する可能性が低くなります。

より一般的にsyncは、内部的に観察可能な効果はありません。ファイルシステムが別のオペレーティングシステムインスタンスの下に保存されているデバイスにアクセスする場合にのみ違いがあります。より明確に言えば、システムの電源syncが切れた場合、再起動後、最後のデータより前に書き込まれたデータのみが使用可能であることが保証されます。

競合状態を取り除くことに関して、ここにいくつかの可能なアプローチがあります:

  • 置換されたすべてのプロセスを明示的に同期します。

    mkfifo sync.pipe
    command > >(tee -- "$stdoutF"; echo >sync.pipe)
           2> >(tee -- "$stderrF"; echo >sync.pipe)
    read line < sync.pipe; read line < sync.pipe
    
  • $stdoutFandを再利用する代わりに、コマンドごとに異なる一時ファイル名を使用$stderrFし、一時ファイルが常に新しく作成されるようにします。

  • プロセス置換をあきらめて、代わりにパイプを使用してください。

    { { command | tee -- "$stdoutF" 1>&3; } 2>&1 \
                | tee -- "$stderrF" 1>&2; } 3>&1
    

    コマンドの戻りステータスが必要な場合、bashはそれをに入れます${PIPESTATUS[0]}

    { { command | tee -- "$stdoutF" 1>&3; exit ${PIPESTATUS[0]}; } 2>&1 \
                | tee -- "$stderrF" 1>&2; } 3>&1
    if [ ${PIPESTATUS[0]} -ne 0 ]; then echo command failed; fi
    
于 2010-12-20T20:21:48.143 に答える
1

私は時々警備員を置きます:

: > >(sleep 1; echo a; touch guard) \
  && while true; do
    [ -f "guard" ] && { rm guard; break; }
     sleep 0.2
  done    
于 2016-05-12T17:15:36.040 に答える
-1

最後の質問に答えるsleep 5代わりにaまたはwhatnotを挿入しますsync

于 2010-12-20T17:41:08.230 に答える