为什么“#!/bin/sh -a”中的 -a 影响 sed 而“set -a”则不影响?

为什么“#!/bin/sh -a”中的 -a 影响 sed 而“set -a”则不影响?

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

#!/bin/sh -a
echo "a" | sed -e 's/[\d001-\d008]//g'

结果是一个错误:

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

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

#!/bin/sh
set -a
echo "a" | sed -e 's/[\d001-\d008]//g'

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

答案1

当使用名称调用 bash 时sh,它做这个:

if (shell_name[0] == 's' && shell_name[1] == 'h' && shell_name[2] == '\0')
    act_like_sh++;

然后后来设置POSIXLY_CORRECTy:

if (act_like_sh)
  {
    bind_variable ("POSIXLY_CORRECT", "y", 0);
    sv_strict_posix ("POSIXLY_CORRECT");
  }

bind_variable调用bind_variable_internal,如果 shell 属性a当时处于打开状态(如果您使用 调用 shell,则会出现这种情况-a),将 shell 变量标记为出口

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

#!/bin/sh -a
echo "a" | sed -e 's/[\d001-\d008]//g'

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

在 GNU sed 中,是字符的转义码,其以 10 为基数的数值为\dNNN神经网络,但在 POSIX 模式下,这在方括号表达式内被禁用,因此[\d001-\d008], 字面意思是字符\,d等,范围是从1\。按照字符代码的顺序,1位于前面\(范围包括除零之外的所有数字,加上所有大写字母,加上一些特殊字符)。但是,在en_US.UTF-8您使用的区域设置中,\排序在 之前1,因此范围无效。

在你的第二个脚本中:

#!/bin/sh
set -a
echo "a" | sed -e 's/[\d001-\d008]//g'

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

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

相关内容