subshel​​l 和 if 块之间的区别

subshel​​l 和 if 块之间的区别

之间有什么区别:

set -e;
./create-git-tag.sh || {
   echo 'Could not create git tag.'
   exit 1;
}

set -e;
if ! ./create-git-tag.sh; then 
    echo 'Could not create git tag.'
    exit 1;
fi

我猜测 if 块不会创建子 shell,因此会在输入 if 块之前退出?它们看起来功能相同,行为上有什么差异吗?

答案1

大括号{ }不会创建子 shell,圆括号会创建:

重击(1)

列表

list 在子shell 环境中执行。

{列表;}

list 只是在当前 shell 环境中执行。

因此,if语句和表单都... || { }没有创建子 shell 的潜力。

子shell环境可能( )如果使用圆括号而不是大括号来创建。仅当第一个命令||返回非零状态(IE。./create-git-tag.sh 失败)。

如果set -e使用,所有形式都表现出相同的行为(当测试命令失败时,shell 立即退出) - 但在幕后,圆括号将创建一个子 shell(在本示例中似乎没有用)。

如果set -e 不是使用,创建子 shell( )意味着子 shell 将退出,但调用 shell 将继续 - 后面的命令仍将被执行。

在所有情况下,只有在测试命令失败时才会输入 echo-exit 命令链(以及圆括号的关联子 shell)。但是制作条件逻辑的目的是某些东西可能会失败,也可能不会 - 这就是你在问题中的措辞没有意义的地方:

我猜测 if 块不会创建子 shell,因此会在输入 if 块之前退出?

if 块“进入”后,它会运行测试命令来确定下一步要做什么。

就我个人而言,我发现该if语句更易于阅读,并且更喜欢在脚本中使用它。当我“交互”使用 shell 时,操作员&&||我可能会使用 in 。if

答案2

我的理解是它们是等价的;在这两种情况下,exit都会终止运行脚本的 shell 实例。

您所拥有的两个版本都不会创建子shell。为了证明这一点,请考虑以下实验:

$ cat version1
#!/bin/bash

set -e

x=7

ls /tmp/does/not/exist &> /dev/null || {
    x=42
}

echo $x


$ ./version1
42
$ cat version2
#!/bin/bash

set -e

x=7

if [ ! ls /tmp/does/not/exist &> /dev/null ]; then
    x=42
fi

echo $x

$ ./version2
42

如果将{ }in更改version1()(如以下版本所示),则会创建一个子 shell。因此,x内部的修改( )不会影响x调用 shell:

$ cat version3
#!/bin/bash

set -e

x=7

ls /tmp/does/not/exist 2> /dev/null || (
    x=42
)

echo $x

$ ./version3
7

相关内容