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命令的状态并$?返回命令的状态cat。如果这是一个管道,我可以使用,PIPESTATUS但这似乎不适用于并行进程。在实际应用中,其中一个(或两个)命令可能会失败。

有没有办法获取并行运行的进程的状态?除了命名管道之外,是否有更好的方法来完成此任务?

答案1

要获取异步命令的退出状态,可以wait在其 pid 上使用:

#!/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/是否成功mkfifo、未加引号的扩展、缺少--s)。

请注意,如果(或在您的情况下代表的dd任何实际命令)在打开写入之前退出,则将无限期地挂起其自己的 fifo只读状态。dd$pipecatopen()

要解决这个问题,您可以$pipe在另一个 fd 上打开 shell,该进程最终将运行,dd确保管道在cat打开它后立即实例化(并假设dd在打开之前不会任意关闭该 fd $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]}

$PIPESTATUS特定于 bash,但还有其他 shell 的替代方案)。

上面, 和 都ddcat在其 fd 3( 的写入端dd和读取端cat)上打开管道,并且它们将打开/dev/fd/3并在管道上提供另一个 fd,就像上面的解决方法一样。我们使用 fds 4 和 5 来恢复两者的原始标准输入和标准输出(尽管这里的cat标准输出否则会恢复test.bin)。

相关内容