bash pipestatus 在反引号命令中?
Posted
技术标签:
【中文标题】bash pipestatus 在反引号命令中?【英文标题】:bash pipestatus in backticked command? 【发布时间】:2013-07-20 12:15:18 【问题描述】:在 bash 中,如果我在反引号内同时执行几个命令,如何找出第一个命令的退出状态?
即在这种情况下,我试图得到“1”。如果我不使用反引号,我可以通过 PIPESTATUS[0] 获得它,但是当我想保存输出时它似乎不起作用:
## PIPESTATUS[0] works to give me the exit status of 'false':
$ false | true;
$ echo $? $PIPESTATUS[0] $PIPESTATUS[1];
0 1 0
## doesn't work:
$ a=`false | true`;
$ echo $? $PIPESTATUS[0] $PIPESTATUS[1];
0 0
更一般地说,我正在尝试完成:将某个程序输出的最后一行保存到变量中,但能够判断程序是否失败:
$ myvar=` ./someprogram | tail -1 `;
$ if [ "what do i put here" ]; then echo "program failed!"; fi
理想情况下,我还想了解正在发生的事情,而不仅仅是答案。
谢谢。
【问题讨论】:
【参考方案1】:问题是反引号会启动一个子shell。您的子 shell 有自己的 $PIPESTATUS[@]
数组,但它不会保留在父 shell 中。这是将其推入输出变量$a
然后将其检索到名为$PIPESTATUS2[@]
的新数组中的技巧:
## PIPESTATUS[0] works to give me the exit status of 'false':
$ false | true
$ echo $? $PIPESTATUS[0] $PIPESTATUS[1]
0 1 0
## Populate a $PIPESTATUS2 array:
$ a=`false | true; printf :%s "$PIPESTATUS[*]"`
$ ANS=$?; PIPESTATUS2=($a##*:)
$ [ -n "$a%:*" ] && a="$a%:*" && a="$a%$'\n'" || a=""
$ echo $ANS $PIPESTATUS2[0] $PIPESTATUS2[1];
0 1 0
这会将子shell的$PIPESTATUS[@]
数组保存为$a
末尾的空格分隔的值列表,然后使用shell变量substring removal提取它(请参阅我给@987654322的更长示例和描述@)。仅当您确实想要保存 $a
的值而不需要额外的状态时才需要第三行(就像在此示例中以 false | true
运行一样)。
【讨论】:
【参考方案2】:我的解决方案是使用 fifos 和内置的 bash “coproc” 从管道中的每个命令中获取消息和状态。我以前从未使用过fifos。 (哦,男孩,下次我在 Fedora 上使用 BashEclipse 时)。它变成了管理任何管道命令的通用机制。我解决了这个问题,但不是 10 或 20 行代码。更像是 200 个 强大的插入式可重复使用解决方案(我花了三天时间才完成)。
我分享我的笔记:
* stderr for all pipe commands goes to the fifos.
If you want to get messages from stdout, you must redirect '1>&2', like this:
PIPE_ARRAY=("cat $IMG.md5" "cut -f1 -d\" \" 1>&2")
You must put "2>/fifo" first. Otherwise it won\'t work. example:
cat $IMG.md5 | cut -f1 -d' ' 1>&2
becomes:
cat $IMG.md5 2>/tmp/fifo_s0 | cut -f1 -d" " 2>/tmp/fifo_s1 1>&2 ; PSA=( "$PIPESTATUS[@]" )
* With more tha one fifo, I found that you must read each fifo in turn.
When "fifo1" gets written to, "fifo0" reads are blocked until you read "fifo1"
I did\'nt use any special tricks like "sleep", "cat", or extra file descriptors
to keep the fifos open.
* PIPESTATUS[@] must be copied to an array immediately after the pipe command returns.
_Any_ reads of PIPESTATUS[@] will erase the contents. Super volatile !
"manage_pipe()" appends '; PSA=( "$PIPESTATUS[@]" )' to the pipe command string
for this reason. "$?" is the same as the last element of "$PIPESTATUS[@]",
and reading it seems to destroy "$PIPESTATUS[@]", but it's not absolutly verifed.
run_pipe_cmd()
declare -a PIPE_ARRAY MSGS
PIPE_ARRAY=("dd if=$gDEVICE bs=512 count=63" "md5sum -b >$gBASENAME.md5")
manage_pipe PIPE_ARRAY[@] "MSGS" # (pass MSGS name, not the array)
manage_pipe ()
# input - $1 pipe cmds array, $2 msg retvar name
# output - fifo msg retvar
# create fifos, fifo name array, build cnd string from $1 (re-order redirection if needed)
# run coprocess 'coproc execute_pipe FIFO[@] "$CMDSTR"'
# call 'read_fifos FIFO[@] "M" "S"' (pass names, not arrays for $2 and $3)
# calc last_error, call _error, _errorf
# set msg retvar values (eval $2[$i]='"$Msg[$i]"')
read_fifos()
# input - $1 fifo array, $2 msg retvar name, $3 status retvar name
# output - msg, status retvars
# init local fifo_name, pipe_cmd_status, msg arrays
# do read loop until all 'quit' msgs are received
# set msg, status retvar values (i.e. eval $3[$i]='"$Status[$i]"'
execute_pipe()
# $1 fifo array, $2 cmdstr, $3 msg retvar, $4 status retvar
# init local fifo_name, pipe_cmd_status arrays
# execute command string, get pipestaus (eval "$_CMDSTR" 1>&2)
# set fifo statuses from copy of PIPESTATUS
# write 'status', 'quit' msgs to fifo
【讨论】:
【参考方案3】:尝试设置pipefail
选项。它返回失败的管道的最后一个命令。一个例子:
首先我禁用它:
set +o pipefail
创建一个perl
脚本 (script.pl
) 来测试管道:
#!/usr/bin/env perl
use warnings;
use strict;
if ( @ARGV )
die "Line1\nLine2\nLine3\n";
else
print "Line1\nLine2\nLine3\n";
在命令行中运行:
myvar=`perl script.pl | tail -1`
echo $? "$myvar"
产生:
0 Line3
这似乎是正确的,让我们看看启用pipefail
:
set -o pipefail
然后运行命令:
myvar=`perl script.pl fail 2>&1 | tail -1`
echo $? "$myvar"
产生:
255 Line3
【讨论】:
以上是关于bash pipestatus 在反引号命令中?的主要内容,如果未能解决你的问题,请参考以下文章
Newtonsoft.JSON 在反序列化数组中被双引号包围的对象时窒息