所以这应该很简单。我正在尝试测试脚本顶部的条件,并在条件失败时退出整个脚本,并且我想在退出时执行两条语句。有了单独的exit
、没有第二条语句,就可以了,但是无论我如何添加第二条语句,我都无法让它完全退出。隐含的修饰规则是这必须全部在一行上。当对脚本的这一行更改没有按预期工作时,我发现了这一点。剧本继续进行。
首先让我展示一下什么做工作。如果 $USER 变量不是“x”,则以下行将完全退出,这很好。我知道这是有效的,因为在终端窗口中输入这一行将关闭该终端窗口(除非您的用户 ID 确实是“x”),所以它实际上是在执行顶级退出:
[ $USER = 'x' ] || exit 1
所以这很好,正如我想要的,只是我想在退出之前回显一条消息;但是,如果我尝试添加回显,则退出不再发生,或者更确切地说,它似乎以“不同的方式”发生,就像在 bash 函数上下文或其他东西中一样。下一行将不是关闭你的终端,这很糟糕。
[ $USER = 'x' ] || (echo "Time to bail" ; exit 1)
我以为分号可能被回声吃掉了,但不,出口似乎被击中了。我怎么知道?我更改了上面的代码,然后回显 $?我看到了我在上面看到的“1”处输入的任何值。当然,我在想要关闭的终端窗口中查看这些值,但它没有关闭。
下一个变体还显示了执行 echo 和第二条语句的第二种方法,但在使用退出时会再次发生完全相同的行为:
[ $USER = 'x' ] || (echo "Time to bail" && exit 1)
我希望这里有人能让这一切不仅不奇怪,而且看起来合理。
那么这是不可能在一行中完成的吗?
( bash --version
:)GNU bash, version 4.3.30(1)-release
答案1
你正在搜索的是这样的:
[ "$USER" = "x" ] || { echo "Time to bail"; exit 1; }
该{ list; }
语句在当前 shell 上下文中执行给定列表中的命令。与符号不同,没有创建子 shell ( list )
。括号之间的调用exit
将退出该子 shell,而不是父 shell 本身。
您问题中的一行或多行 if 语句的示例在语法上是正确的。我无法重现这种行为。有多少行并不重要; if 语句从不在其主体中启动子 shell。
顺便说一句:我在条件中向变量添加了双引号,因为当变量$USER
为空时,构造将扩展为[ = "x" ]
无效。使用双引号它会扩展为[ "" = "x" ]
.
答案2
感谢 @mikeserv 的提示,答案非常简单,并且与认识到括号表示一种非常特殊的分组的重要性有关。括号创建了一个子 shell,这正是我看到缺少所谓的“顶级”出口的原因。
完整的解释是这里,这是关键摘录:
将命令列表放在括号之间会导致创建子 shell 环境...将命令列表放在大括号之间会导致在当前 shell 上下文中执行该列表。
但这里有点不愉快的是,两者不能完全互换,花括号在最后一个花括号之前需要一个分号,而括号则不需要。我正在采用的语法尝试消除分号并使用“&&”形式:
[ $USER == 'x' ] || { echo "保释时间" && exit 1 ; }
总而言之,括号比花括号更好看,而且花括号需要分号,使得单行看起来不像单行。