shell 如何在使用set -e时获得错误代码和命令输出?

zpqajqem  于 2023-08-07  发布在  Shell
关注(0)|答案(4)|浏览(150)

我试图捕获命令的错误代码,并将命令的输出赋给if语句中的变量。我的代码看起来像这样:

if ! ret=$(<some_command>); then
    rc=$?
    echo "<some_command> returned with exit code: $rc"
    echo "$ret"
fi

字符串
在这里,我想将命令的输出分配给ret,并仅将<some_command>的错误代码分配给rc。因为这个脚本有set -e,我不能单独运行这个命令。一旦命令失败,脚本就会退出,但我不想退出脚本,而是将错误代码和错误放入变量中。如何让这个工作?

uidvcgyl

uidvcgyl1#

set -e在这里是一个非问题:它的行为在if内部和任何其他“检查”上下文中被禁用; !是导致你退出状态被抑制的原因。
去掉!,将错误处理移到else子句中:

if ret=$(some_command); then :; else
    rc=$?
    echo "<some_command> returned with exit code: $rc"
    echo "$ret"
fi

字符串
...或者,也许更习惯(如||在命令的退出状态上分支 * 也 * 将其标记为选中并抑制set -e):

ret=$(some_command) || {
  rc=$?
  echo "<some_command> returned with exit code: $rc"
  echo "$ret"
}

z9smfwbn

z9smfwbn2#

!命令只是否定当前退出代码。例如,在!false之后,$?的值将为0。在这种情况下,rc将始终为0。
要检索退出代码以供以后处理,必须在执行命令后收集它。如果你真的坚持使用set -e,IMO是一个坏主意,你可以这样做:

rc=0
ret=$(some_command) || rc=$?
if ((rc > 0))
then
  echo "<some_command> returned with exit code: $rc"
  echo "$ret"
fi

字符串

vc6uscn9

vc6uscn93#

我同意这里的共识--通常不要使用set -e
可以考虑使用trap,例如this
第二,most bash对条件的检查将“消耗”“异常”。我相信有更好的术语,但是你自己去测试一下;如果你立即检查失败,像set -etrap这样的东西通常不会看到失败,你可以显式地处理它。
user 1934428的solution使用双管道来执行此操作,以显式地检查退出状态并在失败时设置值。
要小心-即使只是为了 * 成功 * 而测试也可能产生这种效果。见下文。

$: cat tst
#! bash
set -e
cmd=( bogus command )
# check fail only (#1), success only (#2), both (#3)
"${cmd[@]}" || echo "yep, failed #1"
"${cmd[@]}" && echo "worked fine! #2" # doesn't print
"${cmd[@]}" && echo "worked fine!" || echo "oops! #3"
if "${cmd[@]}"  # the if is a test, "catches" the fail
then echo "won't get here"
else rc=$?
     echo "<${cmd[@]}> returned with exit code: $rc - #4"
fi
# running it without checking here, #5
"${cmd[@]}" # uncaught, set -e kills the script here
echo "This doesn't print! #5"

字符串
cmd阵列只是确保echo不必单独维护的一种简单方法。
运行它看起来像这样:

$: ./tst
./tst: line 5: bogus: command not found
yep, failed #1
./tst: line 6: bogus: command not found
./tst: line 7: bogus: command not found
oops! #3
./tst: line 8: bogus: command not found
<bogus command> returned with exit code: 127 - #4
./tst: line 14: bogus: command not found


希望能帮上忙。

附录

我们完全没有解决输出捕获,但你似乎有;我完全同意避免使用“not”(!)可能更好。

8ftvxx2r

8ftvxx2r4#

试试这个Shellcheck-clean代码:

#! /bin/bash -p

if ! ret=$(some_command); then
    rc=${PIPESTATUS[0]}
    printf '<some_command> returned with exit code: %d\n' "$rc"
    printf '%s\n' "$ret"
fi

字符串

  • 在Bash中使用内置的PIPESTATUS数组是获取否定命令返回状态的常用方法。
  • 请参阅Why is printf better than echo?的公认的优秀答案,以解释为什么我用printf替换echoecho "$var"一般不工作。

相关问题