不需要整行,只需正则表达式中的匹配项


15

我只需要从正则表达式获取匹配项:

$ cat myfile.txt | SOMETHING_HERE "/(\w).+/"

输出必须仅是括号内匹配的内容。

不要以为我可以使用grep,因为它与整行都匹配。

请让我知道该怎么做。

Answers:


12

2件事:

  • 如@Rory所述,您需要此-o选项,因此仅打印匹配项(而不是整行)
  • 此外,您还可以-P选择使用Perl正则表达式,该表达式包含有用的元素,例如向前看 (?= )向后看 (?<= ),这些元素寻找零件,但实际上并不匹配并打印它们。

如果只希望匹配parensis中的部分:

grep -oP '(?<=\/\()\w(?=\).+\/)' myfile.txt

如果文件包含字符串/(a)5667/,则grep将显示'a',因为:

  • /(由找到\/\(,但由于它们位于后面 (?<= ),因此未报告
  • a被匹配并被\w打印(由于-o
  • )5667/被发现b < \).+\/,但是由于它们处于超前状态 (?= ),因此不会报告

18

使用中的-o选项grep

例如:

$ echo "foobarbaz" | grep -o 'b[aeiou]r'
bar

4
真可悲...您是否知道我有多少次sed尝试使用后向引用来做到这一点?
Insyte

10
grep / egrep的o选项仅返回与整个正则表达式匹配的内容,而不仅返回他所要求的()中的内容。
凯尔·布​​兰特

1
但是,无论如何,这是一件非常好的事情:-)
凯尔·布​​兰特

2
@KyleBrandt:只匹配一个部分(例如:parenses),可以通过向前看或后面看来标记其余部分:(?<=)和(?=)
DrYak 2015年

6
    sed -n "s/^.*\(captureThis\).*$/\1/p"

-n      don't print lines
s       substitute
^.*     matches anything before the captureThis 
\( \)   capture everything between and assign it to \1 
.*$     matches anything after the captureThis 
\1      replace everything with captureThis 
p       print it

4

如果只需要括号中的内容,则需要支持捕获子匹配项(命名或编号的捕获组)的内容。我认为grep或egrep不能做到这一点,perl和sed可以做到。例如,使用perl:

如果一个名为foo的文件中有一行,则如下所示:

/adsdds      /

你也是:

perl -nle 'print $1 if /\/(\w).+\//' foo

返回字母a。那可能不是您想要的。如果您告诉我们您要匹配的内容,则可能会获得更好的帮助。$ 1是在第一组括号中捕获的内容。$ 2将是第二组,以此类推。


我只是想匹配括号中的内容。似乎将其传递给perl或php脚本可能是答案。
Alex L

4

因为除了shell之外,您还将问题标记为bash,所以grep之外还有另一种解决方案:

Bash自3.0版以来就有自己的正则表达式引擎,使用的=~运算符与Perl一样。

现在,给出以下代码:

#!/bin/bash
DATA="test <Lane>8</Lane>"

if [[ "$DATA" =~ \<Lane\>([[:digit:]]+)\<\/Lane\> ]]; then
        echo $BASH_REMATCH
        echo ${BASH_REMATCH[1]}
fi
  • 请注意,您必须像这样调用它,bash而不仅仅是sh为了获得所有扩展名。
  • $BASH_REMATCH 将给出与整个正则表达式匹配的整个字符串,因此 <Lane>8</Lane>
  • ${BASH_REMATCH[1]} 将给出与第一组匹配的部分,因此仅 8

亲爱的@DrYak,我希望您不要在这里使用正则表达式来解析XML .. :)
joonas.fi

更糟的是。我正在解析XML和FASTA数据(它们都使用该>符号用于完全不同的目的)的可怕组合,这是由SANSparallel快速大规模对准软件产生的。当然,这两种格式都是隔行扫描而没有任何转义。因此,不可能在此处抛出一些标准XML库。在代码的这一点上,我正在使用Bash regex,因为我只需要提取几个数据,而2个regex对我来说比为这种混乱编​​写专用的解析器做得更好。#LifeInBioinformatics
DrYak

换句话说:在某个点上,使用正则表达式Rathan比提取整个XML探戈更容易提取1个单数
DrYak

哈哈!:)
joonas.fi

2

假设文件包含:

$ cat file
Text-here>xyz</more text

并且您想要介于>和之间的字符</,可以使用以下任一方法:

grep -oP '.*\K(?<=>)\w+(?=<\/)' file
sed -nE 's:^.*>(\w+)</.*$:\1:p' file
awk '{print(gensub("^.*>(\\w+)</.*$","\\1","g"))}' file
perl -nle 'print $1 if />(\w+)<\//' file

全部将打印字符串“ xyz”。

如果要捕获此行的数字:

$ cat file
Text-<here>1234</text>-ends

grep -oP '.*\K(?<=>)[0-9]+(?=<\/)' file
sed -E 's:^.*>([0-9]+)</.*$:\1:' file
awk '{print(gensub(".*>([0-9]+)</.*","\\1","g"))}' file
perl -nle 'print $1 if />([0-9]+)<\//' file


对我而言,至关重要的是要意识到\ d与sed不兼容。您在此处使用[0-9] +是有原因的。:)
user27432 '19

@ user27423不是,但是POSIX字符类(痛苦的阅读愉快的阅读)可以做到:echo 'Text-<here>1234</text>-ends' | sed -E 's|.*>([[:digit:]]+)<.*|\1|'。在某些情况下(例如[0-9]vs. [[:digit:]]),它们无助于提高可读性,而在另一些情况下,我认为它们在帮助方面(例如[ \t\n\r\f\v]vs. [:space:])。
塞缪尔·哈默尔

0

这将满足您的要求,但我认为这不是您真正想要的。我把.*正则表达式的前面放进去,以免在比赛前吃掉任何东西,但这是一个贪婪的操作,因此它只匹配\w字符串中倒数第二个字符。

请注意,您需要转义括号和+

sed 's/.*\(\w\).\+/\1/' myfile.txt
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.