如何将字段名称设置为文件名bash / awk

时间:2016-06-06 16:41:50

标签: bash awk

我有一个包含500列的文件,我需要将每列拆分成一个新文件,同时在所有文件中打印$ 1。下面是一个示例文件,我设法使用下面的bash / awk解决方案:

ID    F1    F2    F4    F4
aa    1    2    3    4 
bb    1    2    3    4
cc    1    2    3    4
dd    1    2    3    4

num=('1' '2' '3' '4')
for i in ${num[@]}; do awk -F "\t" -v col="$i" '{print $1,$col}' OFS="\t"        
Input.txt > ${i}.txt; done

将所需的输出提供为:

1.txt
ID    ID
aa    aa
bb    bb
cc    cc
dd    dd

2.txt
ID    F1
aa    1
bb    1
cc    1
dd    1

....

但是,我无法跟踪哪个文件对应哪个列,因为输出文件名是字段编号而不是字段名。是否可以将字段的标题写为输出文件名的前缀?

ID.txt
ID    ID
aa    aa
bb    bb
cc    cc
dd    dd

F1.txt
ID    F1
aa    1
bb    1
cc    1
dd    1

2 个答案:

答案 0 :(得分:2)

您可以在一个awk脚本中完成所有操作。处理第一行时,将所有列标题放在一个数组中。然后,当您处理行时,您将在循环中从该数组写入文件名。

awk -F'\t' 'NR == 1 { split($0, filenames) }
     {for (col = 1; col <= NF; col++) { 
        file= filenames[col] ".txt"; 
        print $1, $col >> file; 
        close(file) } }' Input.txt

答案 1 :(得分:1)

如果我正确理解您的要求,您似乎非常接近。尝试

num=('1' '2' '3' '4')
for i in ${num[@]}; do
  echo "i=$i"
  awk -F "\t" -v col="$i" -v OFS="\t" '
    NR==1{fName=$(col+1)".out";next}
    {print $1,$(col+1) > fName}' data.txt
done   

1>cat F1.out
aa      1
bb      1
cc      1
dd      1

. . . .

1>cat F4.out
aa      4
bb      4
cc      4
dd      4

修改

如果您需要保留示例输出中显示的标题,请删除;next

修改2

如果您有多个具有相同名称的列,则可以使用>> fName将数据附加到同一文件。用这种技术警告一句话。当您使用> fName时,此&#34;重新启动&#34;每次重新运行脚本时的文件。但是在使用>>时,每次运行脚本时都会附加到每个文件。这可能会导致下游流程出现问题;-) ...因此,您需要添加清理以前运行脚本的代码。

在这里,我们依赖于awk也可以使用> fName将输出写入文件的事实(其中fName已被定义为col的值( Num)+1(跳过第一列值)。

而且,如果你每天要做几千次这样的话,那么值得进一步优化上面的评论,让awk一次读取文件并创建内部循环的所有输出。但是如果你只需要做几次,那么你就可以使用unix / linux的工具将任务分解为可管理的部分&#39;非常合适。

IHTH