未找到 bash 事件尝试匹配并排除 grep 中的括号

未找到 bash 事件尝试匹配并排除 grep 中的括号

我将用很长的一句话来总结:

(foo),(bar,baz(word,right),(end)

我只想打印:

      (bar,baz(word,right

为了匹配第二个括号,我排除第三个后面的词:

$ grep -oP "\\(.*(?!word).*right"

但 Bash 解释了感叹号:

-bash: !word: 未找到事件

保护感叹号单引号失败了grep: missing )

$ grep -oP '\\(.*(?!word).*right'
$ grep -oP '\\((?!word)(.*right)'

保护感叹号反斜杠失败了grep: unrecognized character after (? or (?-

任何想法?

注意:-P适用于 Perl 正则表达式,-o仅打印一行的匹配部分

答案1

单引号和双引号的规则不同。

由于您所展示的原因,双引号不能在 bash 中可靠地使用,因为没有明智的方法来转义感叹号。

$ grep -oP "\\(.*(?!word).*right"
bash: !word: event not found

$ grep -oP "\\(.*(?\!word).*right"
grep: unrecognized character after (? or (?-

第二个是因为 bash 传递\!而不是!grep。显示这个:

$ printf '%s' "\!"
\!

当您尝试使用单引号时,双反斜杠并不意味着转义反斜杠,而是意味着两个反斜杠。

$ printf '%s' '\\(.*(?!word).*right'
\\(.*(?!word).*right

在单引号内,一切都是文字,并且没有转义,因此编写您正在尝试的正则表达式的方法是:

$ grep -oP '\(.*(?!word).*right'

答案2

如果您想从第二个左括号开始匹配,直到(但不包括)下一个右括号:

grep -Po '\(.*?\K\([^)]*'

或者便携式地使用sed

sed -n 's/^[^(]*([^(]*\(([^)]*\).*/\1/p'

要匹配最右边的那个之后(不跟word在最右边的:right

grep -Po '.*\K\((?!word).*right'

答案3

你可以用简单的方法来做到这一点awk

$ echo '(foo),(bar,baz(word,right),(end)' | awk -F'),' '{print $2}'
(bar,baz(word,right

答案4

如果由于某种原因您无法按照 Mikel 的答案中的建议使用单引号,您可以使用 暂时关闭历史扩展set +H(使用 重新打开set -H),如 Glenn jackman 在评论中所建议的。

相关内容