2016-03-03 188 views
1

如果我想从与各种数量的列这样的文件进行搜索:grep和只返回匹配的列

ppl:apple age:5 F add:blabla love:dog 
ppl:tom M add:blablaa love:cat 
ppl:jay age:3 M love:apple 
ppl:jenny acc:jen age:8 F add:blabla 

... 

文件被标签分开,并且我想输出是:

age:5 
age:3 
age:8 
... 

使用grep age:将返回整个行,而使用 cut -f2会返回一些不必要的列:

age:5 
M 
age:3 
acc:jen 

既不cut -f2|grep age:也不grep age|cut -f2:工作

我的数据范围可以从11-23列, 会不会有任何简单的使用sed的grep的或AWK, 千恩万谢

+0

您给出的输入,第二行没有年龄:x。输入数据是这样的。 – Varun

+0

用tab替换T:'sed -n“s /^.* T \(age:[^ T] * \)T * $/\ 1/p”

+0

有些可能不会有年龄:列,总列数不固定 – once

回答

2

grep本身能做到这一点,没有额外的工具,通过使用-o/--only-matching开关。你应该能够只是做:

grep -o '\<age:[0-9]\+' 

为了解释的正则表达式的不常见的部位:

  • \<是零宽度断言,你在一个单词的开头(即是,年龄前面是一个非单词字符或出现在行的开头,但它实际上不符合该非单词字符);这可以防止你匹配,比如说image:123。它在技术上不需要空格,所以它会匹配:age:等;如果这是一个问题,请自行匹配\t并使用cuttr稍后将其删除。
  • \+表示“匹配1个或多个前面的字符类”(即[0-9],因此它匹配一个或多个数字)。 \+等同于重复该类两次,其中第二个副本接着是*,例如, [0-9][0-9]*,除了它更短,一些正则表达式引擎可以更好地优化\+
+3

++;的确是最简单的方法。虽然不符合POSIX标准,但它适用于GNU和BSD/OSX'grep'。 ('-o'是一个非标准选项,而POSIX EREs不支持'\ <'或任何其他种类的字边界断言)。 – mklement0

+1

@ mklement0:感谢您的便携笔记。找不到POSIX'grep'规范。 '\ <'主要是为了安全;如果这种形式的子串不会发生(例如不想匹配'image:'),或者你可以在'\ t'而不是'\ <'上匹配并使用'cut'去除结果中的'\ t'。 – ShadowRanger

+0

对我来说最简单! tks 我可以问一下'\ <\ +' – once

1

您可以使用脚本来处理它的方式如下:

cat file|grep age|awk '{for(i=1;i<22;i++){if($i ~ /^age:/)print $i}}' 
1

ShadowRanger's simple grep-based answer可能是最好的选择。

与两个GNU sed和BSD/OSX sed工作的解决方案:

sed -nE 's/^.*[[:blank:]](age:[0-9]+).*$/\1/p' file 

随着GNUsed可以简化到:

sed -nr 's/^.*\t(age:[0-9]+).*$/\1/p' file 

两个命令都匹配整个输入线,如果它包含一个感兴趣的age:字段,请将其替换为该捕获字段(\1),并打印结果;其他行被忽略。


原来的答复,得到了澄清的要求之前:

假设上线,其中age:本,它始终是第二制表符分隔的领域,awk是最好的解决方案:

awk '$2 ~ /^age:/ { print $2 }' file 
  • $2 ~ /^age:/仅匹配线卫生组织e第二个空格分隔的字段以字面开头age:
  • { print $2 }只需打印该字段。
+0

如果它不总是第二个字段, 对不起,我的例子不够好.. – once

+0

@once:明白了。请在下次提前澄清此类要求。 – mklement0

1

您也可以用sed

sed -nr 's/^.*(age:.).*$/\1/p' input_pattern.txt 

哪里input_pattern.txt包含您的数据。

1

限制搜索的正则表达式来列11〜23:

awk '{ for(i = 11; i <= 23; i++) { if ($i ~ /^age:/) print $i } }' file