【问题标题】:Special meaning of "$a$" in grep commandgrep 命令中“$a$”的特殊含义
【发布时间】:2016-12-11 19:07:05
【问题描述】:

我正在尝试学习 shell 脚本,并且正在尝试不同的东西。我在练习的时候遇到了grep "$a$" file1 并且无法理解输出。

我知道单引号具有字面意义和双引号试图找到特殊含义的区别,例如 $a 应该是变量 $

我有 file1 的内容

#!/bin/sh
a=1
b=1
echo $a
echo $b
for I in 1 2 3 4 5 6 7 8
do
    c=a
    b=$a
    b=$(($a+$c))
    echo $b
done

grep "$a$" file1 给了我整个file1 作为输出 grep '$a$' file1 给了我应该给出的输出,比如以$a 结尾的行。

请解释为什么在使用grep "$a$" 时会输出整个文件内容。

【问题讨论】:

    标签: regex bash shell grep


    【解决方案1】:

    ^$ 开头的grep 模式分别表示开始和结束。

    grep "$a$" file1
    

    $a 经历扩展,因为它在双引号内。在您的情况下,$a 应该是未定义的。所以"$a$" 的结果是$,它匹配每一行的结尾,所以你会得到整个文件作为输出。要验证这一点,请为 a 分配一些测试值,然后运行 ​​grep。

    a="TestValue" # Before running grep
    grep "$a$" file1
    

    我打赌你不会得到任何输出。

    现在,如果您想在双引号内添加文字 '$'。那你需要做

    grep "\$a$" file1 # See the first $ is escaped
    

    上面的命令会给你所有以$a结尾的行

    echo $a
    b=$a
    

    现在,如果您厌倦了转义,您可以很好地使用单引号,如下所示

    grep '$a$' file1
    # The first $ is literal $, and the last one symbolizes end of file.
    # More over variable-expansion doesn't take place inside single quotes.
    

    注意:file1 中的a=1 对 grep 结果没有影响,因为file1 只是grep 的输入。

    【讨论】:

    • OP 定义了a=1 - 或者他们是否在您写完答案后对其进行了编辑?
    【解决方案2】:

    没有特殊含义。

    我在您的代码中没有看到任何 grep。我假设您正在从命令行获取,并且变量 a 未定义。因此,grep "$a$" 扩展为 grep "$"$a 扩展为空),grep $ 匹配每一行,因为 $ 匹配行尾。

    [update] 'expand' 是指 shell 变量扩展。因为$a 在双引号之间,所以shell 将$a 替换为变量a(未定义)的值。您的 grep '$a$' 会产生预期的结果,因为单引号之间的任何字符串始终不会被 shell 触及。试试echo "$a$"echo '$a$'

    【讨论】:

      【解决方案3】:

      "$a$"

      字符串"$a$" 扩展为$a shell 变量的值,后跟文字$(为什么?见下文)。如果$a变量未设置,则其值被解释为空字符串,扩展结果为"$"(只有美元符号)。

      为什么最后一个美元符号没有展开?**

      parameter expansion 的基本形式是"${PARAMETER}"。如果PARAMETER 不是一个多于一位的位置参数(1011 等),并且如果PARAMETER 后面没有跟不被解释的字符,则不需要大括号作为其名称的一部分。由于$ 开始下一个参数扩展、命令替换或算术扩展,因此在我们的例子中它不会被解释为a 参数名称的一部分。

      由于最后一个$ 后面没有任何内容,因此它不符合任何类型的扩展,因此保持原样。

      Grep 如何解释模式

      由于match-end-of-line operator ($) 匹配字符串末尾或字符串中换行符之前的空字符串,因此模式$ 匹配任何行

      因此,如果$a 为空,grep "$a$" file 将匹配并打印file 中的所有行。

      '$a$'

      单引号保护字符串免受任何扩展(特殊字符的解释)。也就是说,字符串按原样传递给命令。

      grep '$a$' file 调用的情况下,模式匹配"$a" 字符串在行尾。下面说明原因。

      正如我们所知,最后一个$ 表示行尾。其余的美元符号根据模式进行解释。它可以解释为文字美元符号,也可以解释为行尾。

      在以下情况下,$ 表示行尾运算符。否则,$ 是普通的。

      • 如果$ 是模式中的最后一个,如foo$
      • syntaxRE_CONTEXT_INDEP_ANCHORS 已设置,位于括号表达式之外。
      • 结束一个开组或交替运算符表达式,例如'\(b$\)',或'\(b$\)\|a'

      自从

      • 我们模式中的第一个 $ 显然不是最后一个,
      • 您使用的是基本的RE_SYNTAX_GREPsyntax,即BRE,
      • 并且不使用开放组/交替,

      $a$ 中的第一个美元符号是普通

      当第一个$不是普通

      这不是普通的,例如在扩展正则表达式的情况下。也就是说,使用-E-P 选项,或者使用egreppgrep 命令,例如(设置了RE_CONTEXT_INDEP_ANCHORS 语法位)。

      转义美元符号

      考虑转义美元符号,即使它在基本正则表达式中被解释为文字 $。它会养成一个好习惯。

      要在单引号中转义美元符号,请使用反斜杠:'\$a$'

      双引号内的反斜杠具有特殊含义,因此您需要对反斜杠本身进行转义:"\\\$a\$"

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-11
        • 2018-05-01
        相关资源
        最近更新 更多