bash 数组 $PIPESTATUS 有问题

Jus*_*tin 5 osx bash pipe io-redirection awk

我正在编写一个脚本(它将在 OSX 上运行,可能没有别的),它基本上只是解析/var/log/accountpolicy.log*日志以获取身份验证时间/计数。初始命令是通过zgrep执行的sudo,它通过管道传输到awk,执行 awk 脚本。命令运行后,我${PIPESTATUS[@]}用来确定是否有任何失败,如果失败,是哪个部分。

这是当前状态的 awk 脚本:

#! /usr/local/bin/awk -f

BEGIN {
  return_code = 0
  if ( length( username ) == 0 ){
    return_code = 2
    exit return_code
  }

  rows = 0
}
{ 
  if ( $8 != sprintf("\"%s\",", username ) ) next

  rows = rows+1
  print $0
} 
END {
  if ( return_code > 0 ) exit return_code
  if ( rows == 0 ) exit 3
}
Run Code Online (Sandbox Code Playgroud)

awk 脚本有一些自定义值验证和退出代码。返回码 1、2 和 3 表示:

  1. awk 失败(由于一些与 awk 相关的原因)
  2. 没有为 awk 指定要解析的用户名
  3. 指定了用户名,但未找到任何值

测试 #1(正常工作)

一个示例执行(隐藏 awk 脚本的输出,因为这个问题特别与返回代码有关):

$ sudo -n zgrep -h AuthenticationAllowed /var/log/accountpolicy.log* 2>/dev/null | awk -v username="${USER}" -f ./parse-accountpoliocy.awk &>/dev/null
$ echo ${PIPESTATUS[@]}
0 0
Run Code Online (Sandbox Code Playgroud)

您可以看到这${PIPESTATUS[@]}表明sudoawk都成功了,这是预期的,因为我知道我有 sudo 访问权限,并且 awk 变量username已设置并具有日志条目。

测试#2(正常工作)

现在,如果我们将 awk 变量更改为不存在username的帐户,则 awk 脚本应退出并返回以下代码:3

$ sudo -n zgrep -h AuthenticationAllowed /var/log/accountpolicy.log* 2>/dev/null | awk -v username="fakeuser" -f ./parse-accountpoliocy.awk &>/dev/null
$ echo ${PIPESTATUS[@]}
0 3
Run Code Online (Sandbox Code Playgroud)

完美的!

测试 #3(问题..)

如果我执行了上面的命令,但忽略了定义usernameawk 变量,那么 awk 脚本应该以返回码 2 退出

$ sudo -n zgrep -h AuthenticationAllowed /var/log/accountpolicy.log* 2>/dev/null | awk -f ./parse-accountpoliocy.awk &>/dev/null
$ echo ${PIPESTATUS[@]}
141 2
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,awk 脚本确实return 2,但现在由于某种原因,sudo/zgrep返回141,尽管命令的那部分根本没有改变......这就是我遇到的问题。

我什至尝试在不隐藏输出(STDOUTSTDERR)的情况下执行命令,结果是相同的,但没有显示错误:

$ sudo -n zgrep -h AuthenticationAllowed /var/log/accountpolicy.log*  | awk -f ./parse-accountpoliocy.awk
$ echo ${PIPESTATUS[@]}
141 2
Run Code Online (Sandbox Code Playgroud)

awk脚本的退出代码如何更改存储在其中的sudo/zgrep命令的退出代码${PIPESTATUS[@]}


环境信息

  • OSx 版本:10.11.6(El Capitan)
  • Bash 版本:4.4.12
  • AWK 版本:GNU Awk 4.1.4

thr*_*rig 6

$ echo $((141-128))
13
$ kill -l | grep 13
13   PIPE Broken pipe                   29   INFO Information request
$ 
Run Code Online (Sandbox Code Playgroud)

所以 141 是 shell 如何将wait(2)包含PIPE信号的 16 位退出状态字(参见)转换为单个数字;在这种exit 3情况下不会发生这种情况,因为通过管道传输的数据已经被处理awk(并且zgrep没有更多内容可以awk通过管道写入)之后会发生这种情况。该exit 2代替发生得很早,而zgrep仍然有它要管的数据awk,所以zgrep被困住了PIPE,当它试图写入awk已消失。