如何以POSIX方式实现'set -o pipefail' - 几乎完成,需要专家帮助

tom*_*jok 8 linux shell command-line posix pipe

我必须以POSIX方式实现BASH"set -o pipefail"选项,以便它适用于各种LINUX/UNIX版本.为了解释一下,该选项使用户能够验证所有管道命令的成功执行.启用此选项后,此命令将启用cat app.log | 如果'cat'失败,grep'ERROR'失败,否则'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 Code Online (Sandbox Code Playgroud)

上面提到的run()函数使用户能够以这样一种方式调用管道命令:run set -o pipefail 如果其中一个命令失败,你会得到$?

但是存在一个问题,它不支持管道之间的命令分组.我想能够调用这样的东西:

run cmd1 \| cmd2 \| cmd3
Run Code Online (Sandbox Code Playgroud)

当我这样做时,调用失败.我无法得到正确的修改来支持命令分组 - 脚本对于我的bash技能来说有点过于复杂......有人可以提供帮助吗?

谢谢!

run()函数的定义使用户能够以这样的方式运行管道命令:

Sam*_*ins 8

用标准C编写自己的shell,或修补标准shell,或将现有shell与-o pipefail之类的东西一起使用。

显然,-o pipefail是应该在标准外壳程序中提供的一项重要功能,如果您问我这些在标准外壳程序中模仿它的技巧是丑陋的,而且比没有用的还糟。

  • 支持“编写您自己的外壳”这一绝妙的主意。 (4认同)

Dac*_*cav 7

我的两分钱:

#!/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/
Run Code Online (Sandbox Code Playgroud)

这件事似乎可以胜任。想法?

  • 让我说清楚。您否决了答案,因为它包含明显的反问句,或者您实际上是否看到了该解决方案不好的原因?您介意详细说明您的反对票吗? (3认同)
  • @jimis - exit 1 退出子 shell :) (3认同)

Jon*_*ler 5

当您输入时:

run echo "test" ; grep "test" \| awk '{print}'
Run Code Online (Sandbox Code Playgroud)

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

run根据需要进行调用,您必须像执行转义一样转义分号|(并且您需要对命令行中的&&||&可能的其他组件进行类似的处理;需要对$(...)或反引号`...`进行处理仔细考虑)。

如果您写:

run echo "test" \; grep "test" \| awk '{print}'
Run Code Online (Sandbox Code Playgroud)

您至少会得到您想要的所有参数run。是否奏效尚有待商;。我还不了解run您显示的代码应该如何工作。

[...后来...]

它执行一些可怕的I / O重定向,但是将由管道符号分隔的命令的每个段包装到一个单独的小象形文字包中。它假设用双引号引起来的参数正确中和了它,但这并不总是正确的(尽管很多时候它是正确的)。