测试后如何保持上次退出状态


8

测试后是否可以保持最后的命令退出状态($?)不变?

例如,我想做:

command -p sudo ...
[ $? -ne 1 ] && exit $?

最后一个exit $?应返回sudo退出状态,但始终返回0(测试的退出代码)。

没有临时变量,是否可以这样做?

另一个示例进一步说明:

 spd-say "$@"
 [ $? -ne 127 ] && exit $?

在这种情况下,我只想找到第一个命令(退出代码!= 127)就退出。而且我想用实际的spd-say退出代码退出(可能不是 0)。

编辑:我忘了提一下,我更喜欢POSIX投诉解决方案以获得更好的可移植性。

我在脚本中使用此结构,在脚本中我想为同一命令提供替代方法。例如,请参阅我的crc32脚本

临时变量的问题在于它们可能会遮盖其他变量,并避免必须使用长名称,这不利于代码的可读性。


不,但是您可以这样做if ! command -p sudo; then exit; fi,您的示例将得到相同的结果。
jordanm 2015年

好的,如果我想测试127代码怎么办?(例如[ $? -ne 127 ] && exit $?
eadmaster

1
@jordanm:真的吗?如果OP已经提供了他想要的代码/逻辑,并且我正确地阅读了该代码/逻辑,则他希望脚本在sudo命令成功后sudo退出(即,如果退出且状态为0)。但是,如果成功,脚本中的脚本将继续运行(不退出)sudo
G-Man说'Reinstate Monica'15

@ G-Man-我很确定询问者的条件实际上是基于的返回,command而不是sudo根本。那就是我想仅在找到第一个命令时退出(退出代码!= 127)的意思,这是找不到调用它的命令时的指定返回command。我想问题在于,sudo作为测试的一部分进行调用可以首先sudo压缩的返回值command,从而使测试倾斜。
mikeserv

Answers:


3

$_将工作在(至少)互动dashbashzshksh (但显然不是在条件语句中的要求)mksh炮弹。其中-仅据我所知- bash并且zsh也将其填充在脚本化的Shell中。它不是POSIX参数-但对于任何现代的交互式shell都相当可移植。

对于更便携式的解决方案,您可以执行以下操作:

command -p sudo ...
eval '[ "$?" = 127 ] || exit '"$?"

从根本上讲,您$?甚至可以在脚本开头测试其值之前,将其初始值扩展到脚本的尾部。

但是无论如何,由于您似乎正在测试是否sudo可以使用来在外壳程序的内置-p 可移植路径字符串中找到该命令command,所以我认为您可以直接使用它。此外,仅仅是明确的,command 不会测试任何位置参数sudo-所以它是唯一的sudo-而不是它调用-这是有关该返回值。

因此,无论如何,如果您要这样做:

command -pv sudo >/dev/null || handle_it
command -p  sudo something or another

...在测试中工作正常,不会在命令sudo运行中返回任何错误,返回的方式可能会使测试结果产生偏差。


9

根据实际需求,有多种选项可以可靠地处理退出状态而不会产生开销。

您可以使用变量保存退出状态:

command -p sudo ...
rc=$?
[ "$rc" -ne 1 ] && echo "$rc"

您可以直接检查成功或失败:

if  command -p sudo ...
then  echo success
else  echo failure
fi

或使用一种case构造来区分退出状态:

command -p sudo ...
case $? in
(1) ... ;;
(127) ... ;;
(*) echo $? ;;
esac

问题中的特殊情况:

command -p sudo ...
case $? in (1) :;; (*) echo $?;; esac

所有这些选件的优势在于它们符合POSIX标准。

(注意:为说明起见,我在echo上面使用了命令;用适当的exit语句替换以匹配所请求的功能。)


评论不作进一步讨论;此对话已转移至聊天
terdon

1
(我想知道为什么最后的评论没有移动到聊天室。)-正如聊天讨论中POSIX引语所详尽解释和支持的(有关详细信息,请参见此处)。1.)("$(get_errnos)")是命令替换的人为添加,其中要求在问题中与实际错误代码进行比较; 2。)标准中明确指出了哪些更改$?(因此没有更改),以及3.)对该结构没有副作用(除非像您所做的那样,您不必要地引入了它们)。-OTOH,请记住,您喜欢的其他答案显然是非标准的。
Janis

1
@mikeserv; 这很烦人(而且容易引起误解!),不仅因为您采用了双重标准!如果您将相同的人工$(get_errnos)代码应用于任何其他解决方案(( exit 42 ); test "$(get_errnos)" -ne $? && echo $_),它们也将不起作用。(您宁愿将我的标准解决方案放于信用不当的地方,而不是其他非标准hack。)-当然,您可以在任何答案中添加任意代码并破坏它。-和WRT的变化$?; 仅仅因为您找不到它并不意味着它不是真的。(我已经在讨论中甚​​至提供了要在POSIX中搜索的关键字。)
Janis,2015年

1
@mikeserv; 但是,这再次倾向于继续(无结果和无休止的)讨论,不应将其放在此处,因为正确地观察到了@terdon。
贾尼斯(Janis)2015年

1
@mikeserv; 我在刚提到zsh(一开始就单独提及;后来又添加了dash)的一开始就说过,鉴于case退出状态和$?POSIX的定义似乎已经定义好,我认为那一定是一个bug 。-同样,在这里,您应用双重标准;另一个hack(例如)既不是标准的,也不能在其他标准shell中可靠地工作(例如in中ksh)。-我的建议是标准的,并且可以在bash(主要在Linux上使用)和ksh(在商业Unix中占主导地位的Shell)中使用。
Janis 2015年

7
command -p ...
test 1 -ne $? && exit $_

使用$_,它扩展为上一个命令的最后一个参数。


1
对于此特定示例有效,但仅在$?$_引用之间没有其他命令时可用。恕我直言,最好坚持使用在其他情况下也可以使用的一致方法(也可以帮助提高代码的可读性)。
Dan Cornilescu

4
外壳被专门命名两次,一次在标题中,一次作为标签。在问题的任何地方都没有提到可移植性,因此我给出了一个在上述外壳中有效的答案。还有哪些其他怪异的限制?
llua 2015年

1
@mikeserv; 如果您错过了它:我说:“这里有关于POSIX的第一条评论。” 必须予以纠正。不多不少。-与您进行了充分的辩论并在其中进行了解释,POSIX很好地定义了其他答案中的所有三个建议。无需在此处重复您的(IMO错误)意见,也无需再次进行争议。
Janis 2015年

1
@mikeserv; 扩展的副作用的case 模式,这在理论上事(但不是在给定的问题)的唯一场所,是构建情况。-在任何情况下,您的shell命令替换都将传播嵌入式命令的结果,通常,如果不涉及任何会产生错误的命令,则其他扩展通常也不会影响返回状态(注意x=${a!b}情况,但此处无关紧要)。- “没有命令名称的命令”是什么意思?
Janis 2015年

1
@mikeserv; 只能通过临时组成不必要的代码来破坏它。如果您采纳建议,而不必引入人为的废话,则绝对没有灰色区域。在这种情况下,要求非常明确:1.执行命令,2.检查退出代码,3.返回退出代码。-你懂吗?-您随意更改了该要求,以构成一个论点。
贾尼斯(Janis)2015年

6

您可以定义(和使用)一个shell函数:

check_exit_status()
{
    [ "$1" -ne 1 ] && exit "$1"
}

然后

command -p sudo ...
check_exit_status "$?"

可以说,这是“作弊”,因为它会$?check_exit_status参数列表中复制它。

这似乎有点尴尬,确实如此。(当您对问题强加任意约束时,有时会发生这种情况。)这似乎不太灵活,但事实并非如此。您可以使其check_exit_status更复杂,添加一些参数来告诉它要对退出状态值进行哪些测试。


0

要回答您的直接问题,不,无法保留 $?不变。这是我怀疑您专注于错误问题的情况之一。临时变量是获得所需效果的标准且首选方式。这种标准太标准了,我建议您放弃(或重新考虑)您认为自己不想使用的任何理由。我非常怀疑是否值得其他任何方法增加额外的复杂性。

如果您只是出于好奇而问,那么答案是否定的。


@mikeserv我不确定我是否理解-您是在谈论手动分配$?还是类似的东西?
David Z

0

这是我的代码片段,用于保留以前的退出状态而无需退出当前脚本/ shell

EXIT_STATUS=1
if [[ $EXIT_STATUS == 0 ]]
then
  echo yes
else
  (exit $EXIT_STATUS)
fi
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.