为什么 A=\"\" grep $A 的行为不像 grep "" ?

为什么 A=\"\" grep $A 的行为不像 grep "" ?

我在 Linux 上,使用 bash。

$ A=\"\"
$ grep $A
nomatch
""
""                         <- (returned by grep)
$ grep ""
imatcheverything
imatcheverything           <- (returned by grep)

我本来期望grep $A表现得像grep ""。为什么它从字面上匹配""?我预料到这一点是因为 shell 似乎一直在grep参与其中;例如(据我所知),grep \\\\首先由 shell 查看,然后将其转换为grep \\.在此检查之后,grep 会查看剪贴簿记录并搜索包含 的行\

我怀疑这与 shell 替换变量和查看引号的顺序有关。如果 shell 在变量替换步骤之前删除引号,则可以解释此行为。


在一个不相关的说明中,我正在寻找一个具有相对复杂的正则表达式的资源(阅读它们,而不是编写它们。理想情况下,他们会问“这个正则表达式做什么?”),最好是 BRE 或 ERE。

答案1

Bash 在扩展参数后不会评估引号。扩展值仅处理分词文件名扩展如果变量没有被引号括起来,但引号不再被重新解释。它们就像任何其他非 IFS 和非 glob 值一样成为“单词”的一部分。在您的示例中,Bash 按原样将参数传递""给 grep,因为它们不是单词拆分,也不是 glob 模式。

答案2

$ A = \"\"
$ grep $A

在 Bash 中,赋值等号周围没有空格,前面没有空格,后面也没有空格。

$ A=\"\"
$ grep $A

答案3

grep ""使用一个空字符串参数调用 grep。

grep $A(即grep \"\")使用一个参数调用 grep,该参数实际上是两个双引号。

如果您想知道 shell 发送给命令的内容,您可以使用一个小脚本来查找,如下所示。

#!/usr/bin/python3

import sys

args = sys.argv[1:] #skip the first one which is the name of the cmd

print(f"Number of args: {len(args)}")

for index, arg in enumerate(args, start=1):
    print(f"Arg {index}: Length: {len(arg)}")
    for char in arg:
        print(f"{ord(char)} {char}")

示例1:

❯ ./showargs.py ""
Number of args: 1
Arg 1: Length: 0

示例2:

❯ A=\"\"
❯ ./showargs.py $A  
Number of args: 1
Arg 1: Length: 2
34 "
34 "

示例3:

❯ ./showargs.py foo \\\\
Number of args: 2
Arg 1: Length: 3
102 f
111 o
111 o
Arg 2: Length: 2
92 \
92 \

相关内容