如何在 grep 中使用 POSIXLY_CORRECT?

How to use POSIXLY_CORRECT in grep?

Bash中有一个变量POSIXLY_CORRECT

POSIXLY_CORRECT

If this variable is in the environment when Bash starts, the shell enters POSIX mode (see Bash POSIX Mode) before reading the startup files, as if the --posix invocation option had been supplied. If it is set while the shell is running, Bash enables POSIX mode, as if the command

set -o posix

had been executed.

我被告知 grep 的某些选项不是 POSIX 所以我在 The Open Group Base Specifications Issue 6 for grep. So I checked the GNU grep manual 中确认并发现:

grep comes with a rich set of options: some from POSIX and some being GNU extensions. Long option names are always a GNU extension, even for options that are from POSIX specifications. Options that are specified by POSIX, under their short names, are explicitly marked as such to facilitate POSIX-portable programming. A few option names are provided for compatibility with older or more exotic implementations.

它还提到:

2.2 Environment Variables

The behavior of grep is affected by the following environment variables.

POSIXLY_CORRECT
If set, grep behaves as POSIX requires; otherwise, grep behaves more like other GNU programs. POSIX requires that options that follow file names must be treated as file names; by default, such options are permuted to the front of the operand list and are treated as options. Also, POSIXLY_CORRECT disables special handling of an invalid bracket expression. See invalid-bracket-expr.

使用部分 长选项名称始终是 GNU 扩展,即使是来自 POSIX 规范的选项 我说:让我们试试变量 POSIXLY_CORRECT 反对。

所以我确实尝试了一些不是 POSIX:

的东西
$ echo "HELLO" | grep --ignore-case 'hello'
HELLO

但令我惊讶的是它也可以设置它:

$ echo "HELLO" | POSIXLY_CORRECT=1 grep --ignore-case 'hello'
HELLO

我做错了什么?集合 POSIXLY_CORRECT 不应该使 grep 无法识别长选项名称吗?

如果使用不是 POSIX:

的选项(例如 -C),也会发生同样的情况
$ POSIXLY_CORRECT=1 grep -C 2 '2' <<< "1
2
3"
1
2
3

和以前一样运行 set -o posix

首先,一般来说,一些 GNU 工具和库函数使用的 POSIXLY_CORRECT 变量是为了更加正确,它不能保证 GNU 工具根据 POSIX.


GNU grep 本身在选项解析时根本不读取 POSIXLY_CORRECT 变量。 GNU grep 使用 glibc 函数 getopt_long 来解析它的选项。此函数尊重 POSIXLY_CORRECT 环境变量,但只是以一种有限的方式。检查 man getopt_long:

POSIXLY_CORRECT

If this is set, then option processing stops as soon as a nonoption argument is encountered.

...和GNU的源代码grep

此行为对于链接到 glibc 并使用 getopt_long 的所有程序都是相同的。它不特定于 grep

来自 GNU grep 手册:

POSIXLY_CORRECT

If set, grep behaves as POSIX requires; otherwise, grep behaves more like other GNU programs. POSIX requires that options that follow file names must be treated as file names; by default, such options are permuted to the front of the operand list and are treated as options. Also, POSIX requires that unrecognized options be diagnosed as "illegal", but since they are not really against the law the default is to diagnose them as "invalid". POSIXLY_CORRECT also disables _N_GNU_nonoption_argv_flags_, described below.

这意味着在环境中设置 POSIXLY_CORRECT 对 GNU grep 的唯一作用是不允许重新排列文件名后出现的选项,以便将它们放在前面.它不会使其不采用非POSIX命令行标志。

让我们试试看:

$ ggrep "hello" myfile -v

$ env POSIXLY_CORRECT=1 ggrep "hello" myfile -v
ggrep: -v: No such file or directory

(GNU grep 在我的 BSD 系统上被称为 ggrep

手册中关于"unrecognized options"的部分是GNU grep默认做的,即-g标志将被诊断为"invalid",两者都带有POSIXLY_CORRECT 而没有。因为例如--ignore-case 是一个 有效选项 (虽然不是 POSIX),这不会被诊断为 "invalid" with POSIXLY_CORRECT.

一般来说,检查外部实用程序的文档以了解它们在 POSIXLY_CORRECT 下的行为方式(如果他们关心的话)。 bash 手册只能告诉你 shell 及其内置命令如何受此环境变量的影响。