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
$?
cat
PIPESTATUS
並列に実行中のプロセスの状態を取得する方法はありますか?名前付きパイプよりもこれを行うより良い方法はありますか?
答え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
$pipe
cat
open()
この問題を解決するには、$pipe
プロセスが最終的に実行される別のfdでシェルを開き、パイプを開いた直後にパイプがインスタンスdd
化されることを確認します(そして、fdが開かれる前にランダムに閉じられていないと仮定します)。cat
dd
$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/n
bash
$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]}
($PIPESTATUS
bashに固有のものですが、他のシェルに代わるものもあります)。
上記と両方のfd 3(書き込みと読み取りの両方)でパイプを開き、上記dd
の回避策と同様に、パイプで別のfdを開いて提供します。私たちはfds 4と5を使って両方の元のstdinとstdoutを復元します(そうでなければstdoutは復元されますが)。cat
dd
cat
/dev/fd/3
cat
test.bin