Bash 名前付きパイプ、並列コマンド、および終了ステータス

Bash 名前付きパイプ、並列コマンド、および終了ステータス

stdout長いプロセスの状態出力を保存できるように、名前付きパイプを使用しようとしています。状態出力用に使用できますが、stderrエラー防止のために保管したいと思います。例は次のとおりです。

#!/bin/bash
pipe=$(mktemp -u)
mkfifo $pipe

dd if=/dev/zero of=$pipe bs=1M count=1024 status=progress & cat $pipe > test.bin

# ¿¿¿ Status of dd command ???

rm $pipe

このコマンドは正確に私がしたいコマンドではありませんが、名前付きパイプを使用してあるプロセスの出力を別のプロセスの入力に供給する組み合わせを示しています。私のアプリケーションでは、ddいくつかの長期実行コマンドがに置き換えられましたcat。これにより、必要な操作が実行されますが、コマンドステータスを取得してコマンドステータスを返すssh方法がわかりません。これがパイプであれば使用できますが、並列プロセスでは機能しないようです。実際のアプリケーションでは、コマンドのいずれか(またはその両方)が失敗する可能性があります。dd$?catPIPESTATUS

並列に実行中のプロセスの状態を取得する方法はありますか?名前付きパイプよりもこれを行うより良い方法はありますか?

ベストアンサー1

非同期コマンドの終了ステータスを取得するには、次のものを使用できますwait

#!/bin/bash -
pipe=$(mktemp -u) || exit
mkfifo -m 600 -- "$pipe" || exit

dd if=/dev/zero of="$pipe" bs=1M count=1024 status=progress &
dd_pid=$!

cat -- "$pipe" > test.bin
cat_status=$?
wait "$dd_pid"
dd_status=$?

rm -f -- "$pipe"

mktemp(また、これらの/ sが成功したかどうかを確認しないか、mkfifo引用されていない拡張、sミスなどのいくつかの明白なバグを修正します--。)

(またはあなたの場合に現れる実際のコマンドは何でもdd)書き込みを開く前に終了すると、独自のfifo読み取り専用状態は無期限に停止します。dd$pipecatopen()

この問題を解決するには、$pipeプロセスが最終的に実行される別のfdでシェルを開き、パイプを開いた直後にパイプがインスタンスdd化されることを確認します(そして、fdが開かれる前にランダムに閉じられていないと仮定します)。catdd$pipe

dd if=/dev/zero 3> "$pipe" of="$pipe" bs=1M count=1024 status=progress &
dd_pid=$!
cat -- "$pipe" > test.bin
cat_status=$?
wait "$dd_pid"
dd_status=$?

同様に、catパイプを開く前に死ぬと同じ対称的な問題が発生し、これは同じ方法で解決することができます。

システムにファイルがある場合は、名前付きパイプの代わりに通常のパイプを使用して終了ステータスを取得することもできます。/dev/fd/n/dev/fd/nbash$PIPESTATUS

{
  dd if=/dev/zero of=/dev/fd/3 bs=1M count=1024 3>&1 >&5 4<&- 5>&- |
    cat /dev/fd/3 3<&0 <&4 4<&- 5>&- > test.bin
} 4<&0 5>&1

dd_status=${PIPESTATUS[0]} cat_status=${PIPESTATUS[1]}

$PIPESTATUSbashに固有のものですが、他のシェルに代わるものもあります)。

上記と両方のfd 3(書き込みと読み取りの両方)でパイプを開き、上記ddの回避策と同様に、パイプで別のfdを開いて提供します。私たちはfds 4と5を使って両方の元のstdinとstdoutを復元します(そうでなければstdoutは復元されますが)。catddcat/dev/fd/3cattest.bin

おすすめ記事