分割一个大的txt文件来执行grep - unix



我工作(unix, shell脚本)的文本文件是数百万字段分开的管道,而不是由nr分隔。像这样:

field1a|field2a|field3a|field4a|field5a|field6a|[...]|field1d|field2d|field3d|field4d|field5d|field6d|[...]|field1m|field2m|field3m|field4m|field5m|field6m|[...]|field1z|field2z|field3z|field4z|field5z|field6z|

所有文本在同一行。

每个文件的字段数是固定的。

(在这个例子中我有field1=name; field2=surname; field3=mobile phone; field4=email; field5=office phone; field6=skype)

当我需要找到一个字段(例如field2)时,像grep这样的命令不起作用(在同一行中)。

我认为一个好的解决方案可以做一个脚本,用"n"分割每6个字段,然后做grep。我是正确的吗?非常感谢!

With awk:

$ cat a
field1a|field2a|field3a|field4a|field5a|field6a|field1d|field2d|field3d|field4d|field5d|field6d|field1m|field2m|field3m|field4m|field5m|field6m|field1z|field2z|field3z|field4z|field5z|field6z|

$ awk -F"|" '{for (i=1;i<NF;i=i+6) {for (j=0; j<6; j++) printf $(i+j)"|"; printf "n"}}' a
field1a|field2a|field3a|field4a|field5a|field6a|
field1d|field2d|field3d|field4d|field5d|field6d|
field1m|field2m|field3m|field4m|field5m|field6m|
field1z|field2z|field3z|field4z|field5z|field6z|

这里可以方便地设置行长度。

您可以使用sed将一行分割成多行:

 sed 's/(([^|]*|){6})/1n/g' input.txt > output.txt

解释:

  • 我们必须使用(){}的重反斜杠转义,这使得代码有点不可读。

  • 但简而言之:

    • s//1之间的术语(([^|]*|){6})(为了可读性删除了反斜杠)将匹配:

      • [^|]*除'|'外的任何字符,重复多次

      • |后接'|'

      • 上面显然是一列,并且用括号()组合在一起

      • 整个组重复6次{6}

      • ,再加上括号(),形成一个完整的

剩下的部分很容易读懂:

  • 1n,即//g之间的部分替换以上(6个字段的整个数据集)

  • 1是指种子表达式中的"第一"组(开始的"第一"组,所以它是6个字段的整个数据集)

  • n是换行符

  • 所以用换行符

  • 替换整个数据集的6个字段
  • 并重复执行(末尾的g)

您可以使用sed将每6个|转换为换行符。

在我的tcsh版本中,我可以这样做:

sed 's/(([^|]+|){6})/1n/g' filename

考虑一下:

> cat bla
a1|b2|c3|d4|
> sed 's/(([^|]+|){6})/1n/g' bla
a1|b2|
c3|d4|

这是正则表达式的工作方式:

  • [^|]为任意非|字符。
  • [^|]+是至少一个非|字符的序列。
  • [^|]+|是至少一个非|字符后跟一个|字符的序列。
  • ([^|]+|)是至少一个非|字符后跟一个|字符的序列,组合在一起
  • ([^|]+|){6}是连续6个这样的组。
  • (([^|]+|){6})是连续的6个这样的组,组合在一起。

替换只是取这个6组的序列,并在末尾添加一个换行符。

我将如何使用awk

awk -v RS="|" '{printf $0 (NR%7?RS:"n")}' file
field1a|field2a|field3a|field4a|field5a|field6a|[...]
field1d|field2d|field3d|field4d|field5d|field6d|[...]
field1m|field2m|field3m|field4m|field5m|field6m|[...]
field1z|field2z|field3z|field4z|field5z|field6z|

只要调整NR%7的字段数你什么适合你。

如果每六行打印一行呢?

$ awk 'BEGIN{FS=OFS="|"} {for (i=1; i<=NF; i+=6) {print $(i), $(i+1), $(i+2), $(i+3), $(i+4), $(i+5)}}' file
field1a|field2a|field3a|field4a|field5a|field6a
field1d|field2d|field3d|field4d|field5d|field6d
field1m|field2m|field3m|field4m|field5m|field6m
field1z|field2z|field3z|field4z|field5z|field6z

解释
  • BEGIN{FS=OFS="|"}设置输入输出字段分隔符为|
  • {for (i=1; i<=NF; i+=6) {print $(i), $(i+1), $(i+2), $(i+3), $(i+4), $(i+5)}}循环遍历6块上的项。每次打印6个。由于print最终写入了新行,那么您就完成了。

如果您想将文件视为多行文件,那么将n作为字段分隔符。例如,要获取第二列,只需执行:

tr | \n < input-file | sed -n 2p

查看哪些列匹配一个正则表达式,执行:

tr | \n < input-file | grep -n regex 

最新更新