使用正则表达式

时间:2017-06-16 19:54:59

标签: regex bash sed

对于三个连续RE的每个完全任意的一组," re1 re2 re3 &#34 ;,我想要一个工具(或一个单行),输出与 re2 相匹配的所有内容。 (\1

我正在寻找一个常用的命令行工具,它将使用任意正则表达式提取信息,例如grep -o,但是可以像上下文一样使用expr match。我在grep -o中想要的功能是对文件进行迭代,只打印匹配,除了我不想打印出上下文;我在expr match中想要的功能是从上下文中提取的功能(即提取子表达式)。基本上我想匹配每个子表达并打印它,只有它出来。

注意:以下只是一个简单的例子。我的问题是一般的问题,可能涉及从引用的材料到提取XML标签,任何你可以编写正则表达式的东西。 ERE很好,PCRE更好。

例如,假设我想在括号内的一行内打印出所有内容,但不想打印括号。如果我grep -Eo '([^()]*?)'我得到了所有的比赛,但他们周围有括号:

输入:

$ grep -Eo '\([^()]*?\)' 
foo (bar) baz (bat)

输出:

(bar)
(bat)

正确:两个孤立的项目。 不正确:他们有parens。

或者我可以使用expr match

$ expr match 'foo (bar) baz (bat)' '.*(\([^()]*\)).*'

这给了我:

bat

正确地剥离了parens,但错过了第一次出现。

我想过如何在sed中做到这一点;一个人可以使用替换,但是sed会在第一次出现时吃掉expr match

$ echo 'foo (bar) baz (bat)' | sed 's/.*(\([^()]*\)).*/\1/g'
bat

此外,我不认为sed旨在从一行输入生成两行或更多行输出(如grep -o所做的那样);它更像是一个逐行工具。如果sed可以选择将\ n 子表达式匹配放入模式空间或保留可行的空间。

我认为这可能在gawk中可行,但它并不简单明了。与sed一样,gawk可以替代;像grep一样,它可以匹配子串;与expr match一样,它在一行中有多个引用有问题(虽然与expr match不同,它有解决方法)。

它可能可以在Perl中完成,但它会涉及一些变得复杂的循环。

通过查看很多相关的SO问题,很多解决方案都会回答特定问题的具体特征,但我想要一个通用的解决方案。

2 个答案:

答案 0 :(得分:1)

如果你有gnu grep,那么你可以使用lookaheads一步完成:

s='foo (bar) baz (bat)'

grep -Po '(?<=\()[^()]*(?=\))' <<< "$s"
bar
bat

或者使用gnu awk:

awk -v FPAT='\\([^()]*\\)' '{for (i=1; i<=NF; i++) {gsub(/[()]/, "", $i); print $i}}' <<< "$s"
bar
bat

或者使用sed:

sed -E 's/[^()]*\(([^()]*)\)/\1:/g' <<< "$s"
bar:bat:

答案 1 :(得分:-2)

受到sendmail *的启发,我决定在一步到位的过程中,也许两个步骤可能有效。解决方案很简单;使用grep -o打印匹配项,使用sed删除不需要的上下文:

$ re='\(([^()]*)\)'; echo 'foo (bar) baz (bat)' | grep -Eo "$re" | sed -r "s/$re/\1/1"
bar
bat

$ re="<([^<>]*)>"; echo "I <strong>really</strong> want <A href="http://foo.com">this</A>" | grep -Eo "$re" | sed -r "s/$re/\1/1"
strong
/strong
A href=http://foo.com
/A

$ re="<[^<>]*>([^<]*)<[^<>]*>"; echo "I <strong>really</strong> want <A href="http://foo.com">this</A>" | grep -Eo "$re" | sed -r "s/$re/\1/1"  
really
this

$ re="'([^']*)'"; echo "His name was 'John', her name was 'Jane'" | grep -Eo "$re" | sed -r "s/$re/\1/1"
John
Jane

你只需要逃避正则表达式中的任何斜杠或做一些事情来解决sed分隔符问题。

* sendmail,或者更确切地说是sendmail附带的宏,有这种不寻常的技术(称为&#34;聚焦&#34;)内部重新排列电子邮件地址并暂时添加无关的语法它们更容易处理。