如何根据第一列awk分割文件

Pau*_*aul 2 unix bash awk sed

我举例说明了我需要做的事情:

INPUT:

name value1 value2 value3
john xxxxx yyyyy qqqqqq
john xxxxx ddddd vvvvvv
john mmmmm jjjjj llllll
paul xxxxx yyyyy qqqqqq
paul ccccc ccccc dddddd
Run Code Online (Sandbox Code Playgroud)

我需要在第一列中保留标题并将其拆分为相同名称的文件.我需要根据第一列继续命名我的输出文件.

输出:

FILE1:john.tsv

name value1 value2 value3
john xxxxx yyyyy qqqqqq
john xxxxx ddddd vvvvvv
john mmmmm jjjjj llllll
Run Code Online (Sandbox Code Playgroud)

FILE2:paul.tsv

name value1 value2 value3
paul xxxxx yyyyy qqqqqq
paul ccccc ccccc dddddd
Run Code Online (Sandbox Code Playgroud)

INPUT和OUTPUT文件是标签分开的.标题总是一样的.

我的解决方案非常复杂和缓慢:

head -1 INPUT > header

awk 'NR>1{print $1}' | sort | uniq > names

while read line

 do grep $line INPUT | cat header - > $line.tsv

< names

done
Run Code Online (Sandbox Code Playgroud)

nu1*_*73R 5

使用awk我们可以写类似的东西,

$ awk 'NR == 1{header = $0; next} 
    !($1 in filename){ print header > ($1".tsv") } 
    NR > 1 { print $0 > ($1".tsv"); filename[$1] }' file
Run Code Online (Sandbox Code Playgroud)

它能做什么?

  • NR == 1{header = $0}如果读取的记录数是1,则这是标题,将其保存以header供以后使用.

  • NR > 1 { print $0 > ($1".tsv"); filename[$1] }如果我们已经读取了多个记录,则将该行的内容打印到文件名$1,即第一列.

    • filename[$1]我们将文件名保存在由文件名索引的关联数组中.该数组用于打印标题.
  • ($1 in filename){ print header > ($1".tsv") }如果我们在filename数组中找不到当前文件名,那么它是第一次出现.所以我们将标题打印到文件中.


编辑

如果要对第二列上的文件进行排序,那么我们可以先对它们进行排序,然后将它们管道化为awk,

$ sort -n -k2 file | awk ....
Run Code Online (Sandbox Code Playgroud)
  • -n 数字排序.
  • -k2 按第二个键排序.

如果标题也是数字,则这可能不起作用.

  • 建议`awk'NR == 1 {header = $ 0; next}!(文件名为1美元){print header> $ 1".tsv"} {print $ 0> $ 1".tsv"; filename [$ 1]}'`以避免为头文件创建文件以匹配OP期望的文件扩展名 (3认同)