如果上一个命令 (tar) 也失败,如何导致 awk 失败?

Foo*_*bar 7 bash pipe awk

我对以下命令有一些问题,该命令提取 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)


Sot*_*oce 8

最近版本中的一种方法bashPIPESTATUS在调用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]}


che*_*ner 6

根本不使用管道。使用命名管道。

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的。


cas*_*cas 5

你真的不需要。您可以使用 PIPESTATUS 数组从管道中的任何程序获取退出代码。您还可以将数组中的所有退出代码相加,以得出整个管道的状态(如果总和非零,则管道中的某些内容失败)。

man bash

PIPESTATUS

一个数组变量(请参阅下面的数组),包含最近执行的前台管道(可能只包含单个命令)中进程的退出状态值列表。


Eri*_*eau 2

我建议您在 tar 命令上添加“ 2>&1 ”,然后在 awk 中,将打印移动到“ END{...} ”子句中,并使用基于捕获错误消息字符串的条件。

或者,你可以做类似的事情

{ tar -xvf some_tar.tar -C a/directory ; echo "RC=$?" } | ...
Run Code Online (Sandbox Code Playgroud)

并扫描“ RC= ”条件并在执行“ printf ”之前评估结果。