我将用很长的一句话来总结:
(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 在评论中所建议的。