如何仅打印匹配行中匹配的(非空)部分,并将每个部分放在相同的输出行上?

如何仅打印匹配行中匹配的(非空)部分,并将每个部分放在相同的输出行上?

man grep

-o, --only-matching
  Print only the matched (non‐empty) parts of a matching line, with each such part on a separate output line.

一个简单的问题:如何仅打印匹配行中匹配的(非空)部分,每个部分都在一个相同的输出线?

答案1

以下是使用 Perl 单行代码完成此工作的方法:

~/dev/perl$ cat file1
blah foo blah bar blah foo
blah bar blah bar
bar blah bar foo foo blah bar foo
~/dev/perl$ perl -ane '@l=$_=~/(foo)/g;print"@l\n"if@l' file1
foo foo
foo foo foo
~/dev/perl$

解释:

perl -ane '             # invoque Perl interpreter
@l=$_=~/(foo)/g;        # match all "foo" (here insert the string to match) on a line and store in an array (@l)
print"@l\n"if@l         # print the array if not empty
' 
file1                   # file to be processed

答案2

使用 grep 和 awk 的另一种可能的解决方案:

└─$ cat file1
blah foo blah bar blah foo
blah bar blah bar
bar blah bar foo foo blah bar foo  

─$ grep -on foo file | awk -F ":" 's != $1 || NR==1{s=$1;if(p){print p};p=$2;next};{p=p" "$2;}END{print p}'
foo foo
foo foo foo

即:
grep -在 foo 文件上--> 匹配模式 foo,并在输出的每一行前加上输入文件中以 1 为基数的行号。如果匹配多个,则重复相同的行号,例如:

└─$ grep -on foo file 
1:foo
1:foo
3:foo
3:foo
3:foo

awk

  1. -F ":"--> 考虑冒号作为分隔符来解析字段
  2. s != $1 || NR==1--> 检查变量是否s与第一个字段的值不同,或者正在分析的行是否是第一行。如果为真,则执行以下操作:
    • s=$1;--> 变量 s 取第一个字段的值(行号)
    • if(p){print p};--> 如果变量p有值,则打印它
    • p=$2;--> 变量p采用第二个字段的值(匹配模式)
    • next--> 进入下一次迭代,并s != $1 || NR==1在下一行开始重新评估条件
  3. {p=p" "$2;}--> 如果步骤 2 中的条件为假(当行号与前一行相同时:同一行上有多个匹配),则变量p将自身的值连接到所分析行的第二个字段(匹配模式)(它们之间有一个空格)。
  4. END{print p}--> 最后,当所有行都分析完毕后,打印变量 p 中保存的最后一个值。

因此,在上述情况下:
1 号线-->1:foo分析:条件为真,因为NR==1s取值1p未取值因此不打印,p 取值 foo,继续分析第二行。
2号线-->1:foo分析:条件为假,因为 s==$1(此行的第一个字段为 = 1,变量s来自1上一步)且 NR==2(我们在第二行)。因此我们继续执行{p=p" "$2;},变量p取其自身值 + " " + $2(即foo),变成foo foo
3号线-->3:foo分析:条件为真,因为s!=$1(确实s1,第三行的第一个字段是 3)。s取值3p被赋值(foo foo来自上一步),因此打印,p取值foo,继续分析第 4 行
4号线-->3:foo分析:条件为假,因为 s==$1(此行的第一个字段为 = 3,变量s来自3上一步)且 NR==4(我们在第 4 行)。因此我们继续执行{p=p" "$2;},变量p取其自身值 + " " + $2(即foo),变成foo foo
5号线-->3:foo被分析:条件为假,因为 s==$1(此行的第一个字段为 = 3,变量s来自3步骤 3)且 NR==5(我们在第 5 行)。因此我们继续执行{p=p" "$2;},变量p取其自身值(即上一步中的 'foo foo')+“”+$2(即foo),变成foo foo foo
结尾--> 没有更多行需要分析。因此,END执行 之后的部分,并打印{print p}变量p(现在包含上一步中的 )。foo foo foo

最终输出:

foo foo
foo foo foo

相关内容