![使用 grep 的两种命令的区别](https://linux22.com/image/878519/%E4%BD%BF%E7%94%A8%20grep%20%E7%9A%84%E4%B8%A4%E7%A7%8D%E5%91%BD%E4%BB%A4%E7%9A%84%E5%8C%BA%E5%88%AB.png)
因此,这里有两个命令:
cat /var/log/dpkg.log | grep " \install\ "
cat /var/log/dpkg.log | grep install
为什么这些命令的输出不同?您能稍微解释一下第一个命令吗?提前谢谢您。
答案1
这两个命令的第一部分(cat FILENAME
)始终相同,只是将指定文件的内容打印到 STDOUT 流。我不会进一步解释它。
我们感兴趣的点是这个grep
部分。
语法grep
:
grep [OPTIONS] PATTERN [FILE...]
您可以传递grep
一些选项来调整其行为(例如,设置使用的 RegEx 风格或控制输出格式),但在您的情况下不会使用这些选项。
下一个单个参数必须是要匹配的模式,其中正则表达式(“RegEx”)或固定字符串(如果grep
使用选项调用-F
)是必需的。在您的示例中,这是install
或"\ install\ "
部分。我将在下一段中解释它。
之后,指定要匹配的数据源。这可以是文件名,也可以什么都没有。在第二种情况下,grep
将从 STDIN 流(标准输入:通常是您用键盘输入的内容)读取,然后|
通过管道 ( ) 传输上一个命令的输出。
如何正确传递“PATTERN”参数?
模式参数必须是单个参数。这意味着,您不能只传递几个单词或任何包含空格或 shell 特殊字符的内容,因为空格在 Bash 中被视为参数分隔符,并且可能在所有其他 shell 中也是如此,而 shell 特殊字符(例如);
会破坏命令。
但是无论如何你都可以通过两种方式将空格包含到模式中以进行匹配:
将要匹配的整个字符串放在单引号 (
'...'
) 或双引号 ("..."
) 中。这样,shell 会将整个引号括起来的字符串解析为一个参数,并将其传递给grep
。使用反斜杠 (
\
) 转义模式中的每个空格。这意味着,在每个你不想被 shell 视为参数分隔符的空格前写一个反斜杠。但请注意,如果你想在模式中使用真正的反斜杠,你也必须对其进行转义,方法是在它前面写另一个反斜杠。
如果我们现在分析两个命令示例的差异grep
,我们会看到它们匹配的差异:
cat /var/log/dpkg.log | grep "\ install\ "
这与模式匹配install
。(请注意前导和尾随空格!)
这里我们可以看到两种方法:用双引号括住整个模式,并用反斜杠转义模式中的空格。老实说,这是多余的,一个就足够了。虽然在这种情况下这样做并没有什么坏处,但你不应该这样做,而应该决定使用一种方法。通常我建议使用引号,因为它更容易阅读。
cat /var/log/dpkg.log | grep install
这与模式匹配install
。(周围没有空格。)
此处的模式仅由单词组成install
,没有其他内容。没有空格。
您的命令之间的区别:
正如我所说,您的第一个示例仅匹配被空格包围的单词install
。如果单词前后有句号或其他字符,则不会匹配。它也不会匹配行首或行末的单词。
第二个示例不关心单词 之前或之后的任何空格install
。它还匹配行的开始和结束以及它周围是否有标点符号。它甚至匹配任何地方包含此字母序列的单词,例如“uninstall”、“reinstall”或“installation”!
正确/有用的反斜杠转义示例:
正如您提供的示例中反斜杠是多余的,这里是相同示例,没有引号,但仅使用反斜杠转义:
cat /var/log/dpkg.log | grep \ install\
或者,如果您想在文件中匹配字符串“I like Ubuntu”/home/you/path with spaces/textfile
而不使用引号,您可以这样做:
grep I\ like\ Ubuntu /home/you/path\ with\ spaces/textfile
您会发现,您还必须转义路径或文件名中的空格 - 或将其括起来。上面的行等于下面的行:
grep "I like Ubuntu" "/home/you/path with spaces/textfile"
答案2
第二种(更简单的)形式将匹配行中任意位置的给定字符串:例如,它将匹配如下字符串安装化,重新安装,安装编辑等
第一个表达式仅匹配安装两端各有一个空格。反斜杠有点像是转移注意力的借口,因为引号已经足够了(而且第一个反斜杠不必要地转义了引号i
而不是空格):但是它本来可以使用只是反斜杠转义为
cat /var/log/dpkg.log | grep \ install\
(注意:上述命令末尾有一个文字空格字符)。
在我看来,在模式中添加一个空格有点不妥:如果模式被其他空格(制表符或行尾)分隔,则不会起作用。更好的选择可能是使用明确的单词边界,例如
grep '\binstall\b' /var/log/dpkg.log
或使用-w
( --word-regexp
) 开关
grep -w 'install' /var/log/dpkg.log
(尽管这些包括连字符和空格 - 因此等价性并不精确)。如果你真的想要用空格分隔模式实例,那么您可以使用[[:space:]]
POSIX 字符类,例如
grep '[[:space:]]install[[:space:]]' /var/log/dpkg.log
答案3
第一个命令:
cat /var/log/dpkg.log | grep " \install\ "
正如@ByteCommander 指出的那样,可能存在拼写错误,命令应该是
cat /var/log/dpkg.log | grep "\ install\ "
install
这将匹配尾部和前导空格均有的字符串。这也可以通过使用 来实现grep -w "install"
。此外,\
使用引号时不需要 。
第二条命令:
cat /var/log/dpkg.log | grep install
此命令还匹配包含的字符串install
。例如“安装编辑”。
测试用例:
测试文件的内容:
foo
bar
foobar
foo bar
跑步:
cat file1.txt | grep foo
foo
foobar
foo bar
cat file1.txt | grep -w foo
foo
foo bar
cat file1.txt | grep "foo "
foo bar