![`cut`:选择包含字符串的列](https://linux22.com/image/89629/%60cut%60%EF%BC%9A%E9%80%89%E6%8B%A9%E5%8C%85%E5%90%AB%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E5%88%97.png)
我有一个大文件,每行有几列。我熟悉使用cut -f -d
按编号选择特定列。
我检查了手册cut
,似乎没有一种方法可以正则表达式匹配列。
我具体想做的是:
- 选择每行的第二列
- 并选择包含字符串“hello”的所有列(可能没有,如果没有,则可能是任何列,并且每行的列不同)
进行此操作最方便的终端工具是什么?
编辑:
简化示例
x ID23 a b c hello1
x ID47 hello2 a b c
x ID49 hello3 a b hello4
x ID53 a b c d
我想要的结果是:
ID23 hello1
ID47 hello2
ID49 hello3 hello4
或者:
ID23 hello1
ID47 hello2
ID49 hello3 hello4
ID53
详细说明给出的示例:
- 列由一个空格定义
- 是否“仅在字符串存在时打印”并不重要,
grep
如果需要的话我可以只打印“hello” - 我们可以假设字符串“hello”永远不会出现在第 1 列或第 2 列中。
答案1
如果行尾的一个空格不会对您造成太大影响:
$ awk '{for(i=1;i<=NF;i++) if(i==2 || $i~"hello") printf $i" ";print ""}' file
ID23 hello1
ID47 hello2
ID49 hello3 hello4
ID53
这不会对“hello”字符串的位置进行任何假设。
答案2
我认为使用像cut
.或者,至少,不容易。这是一个 Perl 解决方案:
$ perl -lane '$k=join " ",grep{/hello/}@F; print "$F[1] $k" if $k' file
ID23 hello1
ID47 hello2
ID49 hello3 hello4
您可以首先使用以下方法来简化grep
:
$ grep hello file | perl -lane 'print "$F[1] ", join(" ", grep{/hello/}@F)'
ID23 hello1
ID47 hello2
ID49 hello3 hello4
解释
该-n
选项指示perl
逐行读取其输入并应用 给出的脚本-e
。该标志为每个调用-l
添加一个换行符 ( ) 。该选项将空格上的输入行拆分到数组中。\n
print
-a
perl
@F
因此,脚本本身正在查找@F
(所有列)匹配的所有元素hello
,并将它们保存为空格分隔的字符串$k
( $k=join " ",grep{/hello/}@F;
)。然后,如果已定义且至少找到一个,则打印第二个字段 ( $F[1]
) 和。$k
$k
hello
第二个版本是相同的,只是我们不需要$k
直接打印,因为我们知道至少有一个hello
总是存在。