awk:按列名拆分文件并将标题行添加到每个文件

Pen*_*nic 6 awk text-processing split

我有一个管道分隔文件a.txt,其中包含一个标题行。第一列包含文件名。

我想a.txt分成几个不同的文件 - 其名称由第一列确定。我还想a.txt在每个文件的顶部重复标题行。

所以我有a.txt

filename|count|age
1.txt|1|15
1.txt|2|14
2.txt|3|1
41.txt|44|1
2.txt|1|3
Run Code Online (Sandbox Code Playgroud)

我想创造 1.txt

filename|count|age
1.txt|1|15
1.txt|2|14
Run Code Online (Sandbox Code Playgroud)

2.txt

filename|count|age
2.txt|3|1
2.txt|1|3
Run Code Online (Sandbox Code Playgroud)

41.txt

filename|count|age
41.txt|44|1
Run Code Online (Sandbox Code Playgroud)

我有一个基本的拆分工作

awk -F\| '{print>$1}' a.txt
Run Code Online (Sandbox Code Playgroud)

但我正在努力弄清楚如何包含标题,有人可以帮忙吗?谢谢!

Adm*_*Bee 6

解决方案是将标题存储在一个单独的变量中,并在新$1值(=文件名)第一次出现时打印它:

awk -F'|' 'FNR==1{hdr=$0;next} {if (!seen[$1]++) print hdr>$1; print>$1}' a.txt 
Run Code Online (Sandbox Code Playgroud)
  • 这会将整个第一行存储a.txt在一个变量中,hdr但不会处理该特定行。
  • 在所有后续行中,我们首先检查是否$1已经遇到该值(=所需的输出文件名),方法是在seen包含各种$1值出现次数的数组中查找它。如果当前$1值的计数器仍然为零,则将标头输出到由 指示的文件$1,然后增加计数器以抑制所有以后出现的标头输出。剩下的你自己已经想通了。

附录:

如果您有多个输入文件,并且都有一个标题行,您可以简单地将它们全部作为awk调用的参数,如

awk -F'|' ' ... ' a.txt b.txt c.txt ...
Run Code Online (Sandbox Code Playgroud)

但是,如果只有第一个文件有标题行,则需要在第一条规则中更改FNRNR

警告

正如 Ed Morton 所指出的,这种简单的方法仅适用于不同输出文件的数量很少(最多 10 个)的情况。GNUawk仍将继续工作,但由于根据需要在后台自动关闭和打开文件而变得更慢;其他awk实现可能只是因为“打开的文件太多”而失败。