如何在Bash/Grep中转义单引号?

28

我想使用grep搜索一个类似这样的字符串:

something ~* 'bla'

我尝试过这个,但是shell会去掉单引号,真是烦人。

grep -i '"something ~* '[:alnum:]'"' /var/log/syslog

什么是正确的搜索方式?


Shell在双引号内删除单引号?我第一次见到这个! :) - Diego Sevilla
他在单引号内嵌套了双引号和单引号:正则表达式以'"开头,而不仅仅是" - Matteo
@Matteo,一开始很难看到 :) - Diego Sevilla
可以是 *如何在单引号字符串内部转义单引号*(2009年。26个答案。1380票)。参见此答案以获得相对简单的语法。 - Peter Mortensen
4个回答

43

如果你确实需要在引号中查找引号中的引号,那么有一些丑陋的结构可以实现。

echo 'And I said, "he said WHAT?"'

代码如预期般运行良好,但对于另一层嵌套,以下不按预期工作

echo 'She said, "And I said, \'he said WHAT?\'"'

相反,您需要转义单引号字符串之外 的内部 单引号:

echo 'She said, "And I said, '\''he said WHAT?'\''"'

或者,如果您更倾向于:

echo 'She said, "And I said, '"'"'he said WHAT?'"'"'"'

它看起来不太美观,但它能工作。 :)

当然,如果你把东西放在变量中,这一切都无关紧要。

[ghoti@pc ~]$ i_said="he said WHAT?"
[ghoti@pc ~]$ she_said="And I said, '$i_said'"
[ghoti@pc ~]$ printf 'She said: "%s"\n' "$she_said"
She said: "And I said, 'he said WHAT?'"
[ghoti@pc ~]$ 

:-)


2
@oldergod,许多echo实现不支持\n。它被bash使用的内置echo支持,但在Bourne兼容模式下(即当bash作为/bin/sh运行时)不起作用,并且在FreeBSD的tcsh中内置的echo中也没有。如果您想要\n始终正常工作,我建议您使用printf。至于您的问题...我的建议是您进行实验...或者更明智的建议是:如果代码不清晰,请使用不同的代码。 - ghoti
1
@mklement0,关于术语,是的,自从我写下那个评论以来,我已经更新了我的口语表达。关于转义序列,我知道你知道这是如何工作的,所以我认为我们之间可能存在误解。在 POSIX 模式下,bash 的内置 echo 命令不会将像 \n 这样的转义序列解释为除了两个字符 \ n 以外的任何内容。尝试一下:bash --posix -c 'echo "one\ntwo"'。我还注意到,来自 coreutils 的 /bin/echo 表现出了我期望的行为。另一方面,我IRC上默认的Ubuntu的shdash,当作为sh启动时,确实会解释转义序列。你测试的时候是不是用的dash - ghoti
1
@mklement0,实际上,这些序列的解释是为了XSI一致性,它(大多数情况下)包含但不等同于POSIX.1。正如您链接的文档所述,“在任何参数中,XSI兼容系统应识别以下字符序列:” 我想了解“POSIX兼容模式”是否指的是POSIX.1、POSIX:2001(SUS),我认为这将包括XSI,还是其他什么东西。 - ghoti
1
感谢您深入挖掘,@ghoti; 为了补充您所发现的:具体而言,XSI是POSIX符合性所需的可选超集(截至当前POSIX标准[POSIX.1-2008,2013版]仍适用)。 getconf _XOPEN_UNIX 可以告诉我们一个给定系统是否支持XSI,getconf _XOPEN_VERSION 报告XSI版本。OSX 10.11和Linux 3.x内核系统都报告支持。Linux没有官方认证,但OSX有(UNIX 03),这就解释了为什么他们费尽心思地调整Bash。 - mklement0
1
非常有趣。作为参考,FreeBSD的/bin/sh基于Almquist shell,确实包括-e选项,并且默认情况下不解释任何XSI序列。文档说明:“当前版本的sh接近于IEEE Std 1003.1(POSIX.1)规范的shell。它仅支持由POSIX指定的功能,以及一些伯克利扩展。”我们能够如此友好相处真是太神奇了。 :-) - ghoti
显示剩余6条评论

14
grep -i "something ~\* '[[:alnum:]]*'" /var/log/syslog

我的机器可以运行。

  • 将第一个*转义以匹配字面上的*,而不是将其作为零个或多个匹配字符:
    ~*会匹配零个或多个~,而
    ~\*会匹配在something之后的表达式~*
  • :alnum:周围使用双方括号(参见此处示例)
  • [[:alnum:]]之后使用*来匹配单引号之间的一个字符以及其中的几个字符
  • 单引号根本不需要转义,因为它们包含在由双引号限定的表达式中。

1
  • 字符类使用[[:alnum:]](两个方括号)指定
  • [[:alnum:]]仅匹配一个字符。要匹配零个或多个字符,请使用[[:alnum:]]*
  • 您可以使用" "引用正则表达式:

    grep -i "something ~\* '[[:alnum:]]*'" /var/log/syslog
    

Matteo


@Matteo - 当然可以,如果它的意思是字面上的解释。~* 表示“零个或多个'~'字符”。 - Graham
@Graham,感谢您的纠正。我错过了他要寻找字面上的“*”。 - Matteo

0

根据您的表达,似乎您先使用了单引号',然后使用了双引号"。如果您想转义单引号,可以使用'并对其进行转义,或者使用双引号。此外,正如Matteo所评论的那样,字符类具有双方括号。两种方式都可以:

grep -i "something \~\* '[[:alnum:]]+'" /var/log/syslog

或者

grep -i 'something ~* \'[[:alnum:]]+\'' /var/log/syslog

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接