Shell 如何实施';设置-o管道故障';以POSIX的方式-即将完成,需要专家帮助

Shell 如何实施';设置-o管道故障';以POSIX的方式-即将完成,需要专家帮助,shell,command-line,pipe,posix,Shell,Command Line,Pipe,Posix,我必须以POSIX的方式实现BASHset-opipefail选项,以便它能够在各种LINUX/UNIX风格上工作。为了解释一下,此选项使用户能够验证所有管道命令的成功执行。启用此选项后,如果cat失败,则此命令cat app.log | grep“ERROR”将失败,否则cat错误将被抑制 因此,我在这里找到了一个非常好的解决方案: 上述run()函数使用户能够以以下方式调用管道命令: run cmd1 \| cmd2 \| cmd3 如果其中一个命令失败,您将在$? 但是,存在一个问题,它

我必须以POSIX的方式实现BASH
set-opipefail
选项,以便它能够在各种LINUX/UNIX风格上工作。为了解释一下,此选项使用户能够验证所有管道命令的成功执行。启用此选项后,如果
cat
失败,则此命令
cat app.log | grep“ERROR”
将失败,否则
cat
错误将被抑制

因此,我在这里找到了一个非常好的解决方案:

上述
run()
函数使用户能够以以下方式调用管道命令:

run cmd1 \| cmd2 \| cmd3
如果其中一个命令失败,您将在
$?

但是,存在一个问题,它不支持管道之间的命令分组。我希望能够调用如下内容:

run echo "test" ; grep "test" \| awk '{print}'
{ cmd1 ; echo $? > status1 ; } | cmd2 && grep -q '^0$' status1 }
当我这样做时,调用失败。我无法得到正确的修改来支持命令分组——脚本对于我的bash技能来说有点太复杂了

有人能帮忙吗

谢谢

键入时:

run echo "test" ; grep "test" \| awk '{print}'
您使用参数
echo
“test”
调用
run
;然后用参数调用
grep
“test”、
|
awk
{print}
。通常,
grep
不会找到任何名为
awk
{print}
的文件

要想调用
run
,您必须像调用
一样避开分号(并且您需要对
&
|
&
以及命令行的其他组件执行类似的操作;
$(…)
或backticks
`……`
需要仔细考虑)

如果你写:

run echo "test" \; grep "test" \| awk '{print}'
您将至少获得所有要运行的参数。届时它是否有效仍有争议;我还不明白你展示的
运行
代码应该如何工作

[……以后……]


它进行了一些可怕的I/O重定向,但将由管道符号分隔的命令的每个部分包装成一个单独的小象形文字包。它假设在一个参数周围加上双引号可以正确地抵消它,但这并不总是正确的(尽管它在很多时候都是正确的)。

您的想法的核心应该包括以下内容:

run echo "test" ; grep "test" \| awk '{print}'
{ cmd1 ; echo $? > status1 ; } | cmd2 && grep -q '^0$' status1 }
从长远来看,这将是:

{ cmd1 ; echo $? > status1 ; } |  \
{ cmd2 ; echo $? > status2 ; } |  \
  # ... and so on                 \
  cmdN                         && \
  # ^ note lack of wrapper        \ 
grep -q '^0$' status1 &&          \
grep -q '^0$' status2 &&          \
  # ... and so on, to N-1

我错过什么了吗

my script.sh

#/垃圾箱/垃圾箱
set-e
cat app.log | grep“错误”
printf'它永远不会打印这个。\n'
$。/my-script.sh
cat:app.log:没有这样的文件或目录
我的两分钱:

#!/bin/sh

# Saving the pid of the main shell is required,
# as each element of the pipe is a subshell.
self=$$

lots_and_fail() {
    seq 100
    return 1
}

{ lots_and_fail || kill $self; } | sed s/7/3/

这东西似乎很管用。想法?

不在bash中的管道之间对命令进行分组<代码>(…;…)
{…;…;}
执行。
设置-o pipefail
<代码>设置-e不同。这是可能的,但可能比它的价值付出更多的努力。Ksh还支持pipefail,mksh支持
PIPESTATUS
,可轻松用于实现pipefail。我会认真考虑使用不同的语言,然后尝试在POSIX S. @ CopoBa这是我的意思。你是对的。这也不起作用。@ormaj我需要一个一致且单一的方法来处理这个问题。run()方法很好,所以我认为添加分组不需要花费太多的精力。你否决了答案,因为它包含一个明显的反问句,或者你真的看到了这个解决方案不好的原因吗?你介意详细说明你的否决票吗?聪明。但是如果使用
exit 1
?@jimis-exit 1退出子shell:)而不是
kill
,它为什么不起作用呢?如果将guts包装到函数中,它会更好一些:
try(){set-e;trap'kill$$exit;eval“$”}
。并将其用作
try cmd1 |。。。cmdN
@jsxt:很高兴看到,的最后一句话可能也适用于此吗?:“它假设在参数周围加上双引号可以正确地抵消它,这并不总是正确的(尽管很多时候都是正确的)。”[最初指的是OP]。或者
eval“$@”
是否使其完全透明?是的,您忽略了一个事实,即默认情况下管道的状态仅为最后一个命令的状态。因此,
cat app.log | grep'ERROR'| cat
将始终成功,即使前两个命令失败。