如何在单个语句中检查命令退出状态是否为零且 stderr 是否为空?

How to check that both command exit status is zero and stderr is empty in a single statement?

有些命令向 stderr 写入无关紧要的警告,但 return 退出状态 0

有没有办法检查命令退出状态是 0 stderr 是空的,没有创建临时文件和一个单一的语句?

我建议:

stderr=$(your_command 2>&1 >/dev/null)
[[ $? == 0 ]] && [[ ${#stderr} == 0 ]] && echo okay

希望以下内容对您有所帮助。

 res=$(./test.out 2 >&1)
 if [ $? -eq 0 ];then
    stdout=$res
    echo $stdout
 else
    return_code=$?
    std_err=$res
    echo $stderr 
 fi

C

对应的test.c文件
   #include <stdio.h>
   int main ( ) {
       printf( "hello " );
       fprintf( stderr, "HELP!" );
       printf( " world\n" );
       return 1;
   }

由于 set -o pipefail 的工作方式,如果 stderr 上有任何内容,您可以在管道中获取 stderr 并以非零退出状态从管道退出。所以基本上 pipefail 执行二进制和-ing 或退出状态 - 如果命令以非零退出状态退出,则 pipefail 以该状态退出管道,如果命令以零退出状态退出,则正确管道的一侧将以非零退出状态失败,因此整个管道将以非零退出状态退出。

# Usage: exit_if_nonzero_or_stderr command [args...]
# Executes the command [args...] and 
# exits with nonzero exit status
# if the command exits with nonzero exit status
# __or__
# the command outputs anything on stderr.
exit_if_nonzero_or_stderr() {
        (       
                set -o pipefail
                { "$@" 1>&3 ;} 2>&1 | {
                        if IFS= read -r line; then
                                printf "%s\n" "$line"
                                cat 
                                exit 1
                        fi
                } >&2
        ) 3>&1
}

针对所有组合进行测试:

tester() { 
        for i in \
                'echo 1; true;' \
                'echo 1; false;' \
                'echo 1; echo 2 >&2; true;' \
                'echo 1; echo 2 >&2; false;'
        do
                eval "f() { $i }"
                set -o pipefail
                exit_if_nonzero_or_stderr f 2> >( \
                        sed 's/^/stderr: /' >&2) | 
                        sed 's/^/stdout: /';
                echo "f() { $i } -> exit status: $?";
        done
}
tester

tester 输出:

stdout: 1
f() { echo 1; true; } -> exit status: 0
stdout: 1
f() { echo 1; false; } -> exit status: 1
stderr: 2
stdout: 1
f() { echo 1; echo 2 >&2; true; } -> exit status: 1
stdout: 1
stderr: 2
f() { echo 1; echo 2 >&2; false; } -> exit status: 1

替代实现和更冗长和更多内存消耗但更多 posix-ish 你可以抓住 stderr 到一个变量并检查它是否非零:

exit_if_nonzero_or_stderr2() {
        local stderr ret
        # redirect stdout to output with temporary file descriptor
        # and grab stderr 
        { stderr=$({ "$@" 1>&3 ;} 2>&1 ) ;} 3>&1
        # remember return value
        ret=$?
        # if theres anything on stderr, output it
        if [[ -n "$stderr" ]]; then
                cat <<<"$stderr" >&2
                # if stderr, always nonzero
                return 1
        fi
        # else we return with the exit status of the command
        return "$ret"
}

感谢 and 的评论:

if stderr=$(command 2>&1 >/dev/null) && test -z "$stderr"; then echo "ok"; fi

command 2>&1 >/dev/nullstderr 被重定向到 stdout 之前的位置,stdout 本身被重定向到 /dev/null。 然后将stderr赋值给stderr=$(command 2>&1 >/dev/null)中的stderr变量,这次赋值的退出码就是command中的那个,所以在[=20中使用了=].然后,如果 command 的退出代码为零(并且仅在这种情况下),则检查第二个条件 (test -z "$stderr") - 测试 $stderr 变量是否为零长度字符串.