我对以下命令有一些问题,该命令提取 tar 文件并打印每秒提取的文件数量:
tar -xvf some_tar.tar -C a/directory | awk 'systime() > lasttime { lasttime = systime(); printf "%d files\n", NR; fflush(stdout) }'
Run Code Online (Sandbox Code Playgroud)
即使 tar 命令失败,awk 命令仍然会返回 0,这是不希望的,因为它并不能反映 tar 命令失败。
我该如何解决这个问题?
ilk*_*chu 16
如果您只想查看管道中是否有任何命令失败,请设置该pipefail
选项。除了 Bash 之外,ksh、zsh 和 Busybox(至少)也支持它。设置该选项后,管道的退出状态是相关命令返回的最左边的非零退出状态。
$ set -o pipefail
$ (exit 123) | true
$ echo $?
123
Run Code Online (Sandbox Code Playgroud)
或者管道只是有条件的(这应该说“它失败了”):
set -o pipefail
if false | true; then
echo it succeeded
else
echo it failed
fi
Run Code Online (Sandbox Code Playgroud)
最近版本中的一种方法bash
是PIPESTATUS
在调用tar|awk
命令管道后检查数组变量中的值。根据 bash 手册页:
PIPESTATUS
An array variable (see Arrays below) containing a list of exit status
values from the processes in the most-recently-executed foreground
pipeline (which may contain only a single command).
Run Code Online (Sandbox Code Playgroud)
因此 tar 的退出代码将在 中${PIPESTATUS[0]}
,而 awk 的退出代码将在 中${PIPESTATUS[1]}
。
根本不使用管道。使用命名管道。
mkfifo p
awk '...' < p &
tar -xvf some_tar.tar -C a/directory > p
echo $?
Run Code Online (Sandbox Code Playgroud)
该awk
命令在后台运行,阻塞直到tar
开始写入命名管道。一旦tar
退出并关闭管道的末端,awk
将在读取从其末端剩余的内容后退出。该echo
命令将报告tar
的退出状态,而不是awk
的。
你真的不需要。您可以使用 PIPESTATUS 数组从管道中的任何程序获取退出代码。您还可以将数组中的所有退出代码相加,以得出整个管道的状态(如果总和非零,则管道中的某些内容失败)。
从man bash
:
PIPESTATUS
一个数组变量(请参阅下面的数组),包含最近执行的前台管道(可能只包含单个命令)中进程的退出状态值列表。
我建议您在 tar 命令上添加“ 2>&1 ”,然后在 awk 中,将打印移动到“ END{...} ”子句中,并使用基于捕获错误消息字符串的条件。
或者,你可以做类似的事情
{ tar -xvf some_tar.tar -C a/directory ; echo "RC=$?" } | ...
Run Code Online (Sandbox Code Playgroud)
并扫描“ RC= ”条件并在执行“ printf ”之前评估结果。