为什么 "#!/bin/sh -a" 中的 -a 会影响 sed 而 "set -a" 不会?

Rod*_*igo 20 shell sed options shell-script

如果我运行以下 .sh 文件:

#!/bin/sh -a
echo "a" | sed -e 's/[\d001-\d008]//g'
Run Code Online (Sandbox Code Playgroud)

结果报错:

sed: -e 表达式 #1, char 18: 无效范围结束

但是如果我运行以下 .sh 文件:

#!/bin/sh
set -a
echo "a" | sed -e 's/[\d001-\d008]//g'
Run Code Online (Sandbox Code Playgroud)

它运行没有错误。第二个代码不应该等同于第一个代码吗?为什么第一个错误?

Mar*_*ick 31

当使用 name 调用 bash 时sh,它会执行以下操作

if (shell_name[0] == 's' && shell_name[1] == 'h' && shell_name[2] == '\0')
    act_like_sh++;
Run Code Online (Sandbox Code Playgroud)

然后POSIXLY_CORRECTshell 变量设置为y

if (act_like_sh)
  {
    bind_variable ("POSIXLY_CORRECT", "y", 0);
    sv_strict_posix ("POSIXLY_CORRECT");
  }
Run Code Online (Sandbox Code Playgroud)

bind_variable调用bind_variable_internal,如果当时 shell 属性a处于开启状态(如果您使用 调用 shell 就会如此-a),则将 shell 变量标记为导出的

所以在你的第一个脚本中:

#!/bin/sh -a
echo "a" | sed -e 's/[\d001-\d008]//g'
Run Code Online (Sandbox Code Playgroud)

sedPOSIXLY_CORRECT=y在其环境中调用 with ,这将使其抱怨[\d001-\d008]. (如果给 sed--posix选项,也会发生同样的事情。)

在GNU sed中,是用于在其数值的字符的转义码碱-10是NNN,但在POSIX模式,这是一个括号表达式中被禁止,因此,装置字面上字符,等,具有范围从被到。按照字符代码的顺序,在之前(并且范围包括除零以外的所有数字,加上所有大写字母,加上一些特殊字符)。但是,在您使用的语言环境中,排序在 之前,因此范围无效。\dNNN[\d001-\d008]\d1\1\en_US.UTF-8\1

在你的第二个脚本中:

#!/bin/sh
set -a
echo "a" | sed -e 's/[\d001-\d008]//g'
Run Code Online (Sandbox Code Playgroud)

即使POSIXLY_CORRECT在 shell 中设置,它也不会导出,因此 sed 在没有POSIXLY_CORRECT环境的情况下被调用,并且 sed 使用 GNU 扩展运行。

如果您export POSIXLY_CORRECT在第二个脚本的顶部附近添加,您还会看到 sed 抱怨。

  • 对我来说,这是一个错误。 (6认同)
  • FWIW,Bash 似乎也没有记录它会自行设置`POSIXLY_CORRECT`。[POSIX模式的效果列表](https://www.gnu.org/software/bash/manual/html_node/Bash-POSIX-Mode.html)和[变量描述](https ://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html#index-POSIXLY_005fCORRECT) 只说设置它会将 shell 更改为 POSIX 模式,而不是相反。 (4认同)
  • @StevenPenny,但是当 shell 启动时,环境中的 `POSIXLY_CORRECT` _isn't_,并且脚本没有设置它。外壳可以。它无处不在地创建了一个环境变量,这是非常糟糕的,因为它在它应该在的模式下这样做,并试图符合标准。 (3认同)