如何在POSIX的方式实现“设定-o pipefail” - 几乎做到了,请高手帮忙需要(How

2019-08-02 00:00发布

我要实现的BASH set -o pipefail在POSIX方式选项,以便它可以在不同的Linux / UNIX版本。 要解释一下,这个选项允许用户检查所有管道命令的成功执行。 启用这个选项命令cat app.log | grep 'ERROR' cat app.log | grep 'ERROR' ,如果失败cat失败,否则, cat被抑制的错误。

于是,我找到了一个非常好的解决方案在这里: 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()函数使得用户能够调用这样一种方式的管道命令:

run cmd1 \| cmd2 \| cmd3

如果其中一个命令失败,你得到它在$?

然而有,它不支持管道之间的命令分组的问题。 我希望能够调用是这样的:

run echo "test" ; grep "test" \| awk '{print}'

当我这样做,则调用失败。 我不能得到正确的修改,以支持命令的分组 - 剧本是我的bash技能有点太复杂...

有人能帮忙吗?

谢谢!

Answer 1:

如果键入:

run echo "test" ; grep "test" \| awk '{print}'

调用run的论点echo"test" ; 然后调用grep与参数"test"|awk{print} 。 通常情况下, grep是不会找到任何所谓的文件|awk{print}

要调用run ,你想,你就必须像你这样的逃脱分号| (和你需要的做的事情同样&&||&并可能是一个命令行的其他组件;的处理$(...)或反引号`...`需约认真思考)。

如果你写的:

run echo "test" \; grep "test" \| awk '{print}'

你至少会得到所有你意的参数run 。 无论即可工作是值得商榷的; 我还不知道该怎么run ,你表现的代码应该工作。

[...后来...]

它一些可怕的I / O重定向,而是包通过管道符号分离成象形文字的一个单独的小数据包的命令的每一段。 它假定围绕论点包装双引号正确中和它,这并非总是如此(虽然它是真的有很多的时间)。



Answer 2:

写在标准C自己的壳,或修补标准的外壳,或使用现有的外壳采用类似-o pipefail。

显然-o pipefail是应该在标准shell的一个重要特征,如果你问我这些黑客模仿它在标准的外壳是丑陋的和有害无益。



Answer 3:

你的想法的核心或许应该包括这样的事情:

{ 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


文章来源: How to implement 'set -o pipefail' in a POSIX way - almost done, expert help needed