如何以POSIX方式实现'set -o pipefail'-差不多完成了,需要专家的帮助 [英] How to implement 'set -o pipefail' in a POSIX way - almost done, expert help needed
问题描述
我必须以POSIX方式实现BASH set -o pipefail
选项,以便它可以在各种LINUX/UNIX风格上运行.稍微说明一下,该选项使用户可以验证所有管道命令的成功执行.启用此选项后,如果cat
失败,此命令cat app.log | grep 'ERROR'
将失败,否则将抑制cat
错误.
I have to implement the BASH set -o pipefail
option in a POSIX way so that it works on various LINUX/UNIX flavors. To explain a bit, this option enables the user to verify the successful execution of all piped commands. With this option enabled this command cat app.log | grep 'ERROR'
fails if cat
fails, otherwise the cat
error is suppressed.
因此,我在这里找到了一个非常不错的解决方案: http://cfaj.ca /shell/cus-faq-2.html
So, I found a really nice solution here: http://cfaj.ca/shell/cus-faq-2.html
run() {
j=1
while eval "\${pipestatus_$j+:} false"; do
unset pipestatus_$j
j=$(($j+1))
done
j=1 com= k=1 l=
for a; do
if [ "x$a" = 'x|' ]; then
com="$com { $l "'3>&-
echo "pipestatus_'$j'=$?" >&3
} 4>&- |'
j=$(($j+1)) l=
else
l="$l \"\$$k\""
fi
k=$(($k+1))
done
com="$com $l"' 3>&- >&4 4>&-
echo "pipestatus_'$j'=$?"'
exec 4>&1
eval "$(exec 3>&1; eval "$com")"
exec 4>&-
j=1
while eval "\${pipestatus_$j+:} false"; do
eval "[ \$pipestatus_$j -eq 0 ]" || return 1
j=$(($j+1))
done
return 0
}
上述run()
函数使用户可以通过以下方式调用管道命令:
The above-mentioned run()
function enables the user to invoke the piped commands in such a way:
run cmd1 \| cmd2 \| cmd3
如果其中一个命令失败,则在$?
If one of the commands fails you get it in $?
但是,存在一个问题,它不支持管道之间的命令分组.我希望能够调用这样的内容:
There is a problem however, it does not support the grouping of commands between pipes. I want to be able to invoke something like this:
run echo "test" ; grep "test" \| awk '{print}'
当我这样做时,调用失败.我无法进行正确的修改来支持命令分组-对于我的bash技能而言,脚本有点太复杂了...
When I do it, the invocation fails. I cannot get the right modification to support the grouping of commands -- the script is a bit too complex for my bash skills...
有人可以帮忙吗?
谢谢!
推荐答案
键入时:
run echo "test" ; grep "test" \| awk '{print}'
使用参数echo
和"test"
调用run
;然后使用参数"test"
,|
,awk
和{print}
调用grep
.通常,grep
不会找到任何名为|
,awk
或{print}
的文件.
you invoke run
with the arguments echo
and "test"
; then you invoke grep
with arguments "test"
, |
, awk
and {print}
. Typically, grep
is not going to find any of the files called |
, awk
or {print}
.
要根据需要调用run
,您必须像使用|
一样转义分号(并且您需要对&&
或||
或$(...)
或反引号`...`
的处理需要仔细考虑).
To invoke run
as you wanted, you'd have to escape the semi-colon like you did the |
(and you'd need to do things similarly for &&
or ||
or &
and possibly other components of a command line; the handling of $(...)
or backticks `...`
needs to be thought about carefully).
如果您写:
run echo "test" \; grep "test" \| awk '{print}'
您至少会得到要用于run
的所有参数.是否奏效尚有待商;.我还不了解您显示的run
代码应该如何工作.
you will at least get all the arguments you intended to run
. Whether it then works is debatable; I don't yet understand how the run
code you showed is supposed to work.
[...稍后...]
它执行一些令人恐惧的I/O重定向,但是将由管道符号分隔的命令的每个段包装到一个单独的小象形文字包中.它假设用双引号引起来的参数正确中和了它,但这并不总是正确的(尽管很多时候它是正确的).
It does some fearsome I/O redirections, but wraps each segment of a command separated by a pipe symbol into a separate little packet of hieroglyphs. It assumes that wrapping double quotes around an argument neutralizes it correctly, which is not always true (though it is true a lot of the time).
这篇关于如何以POSIX方式实现'set -o pipefail'-差不多完成了,需要专家的帮助的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!