如何将字段名设置为文件名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

您可以在一个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

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

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时,每次重新运行脚本时都会"重新启动"文件。但是,当使用>>时,每次运行脚本时都会将其附加到每个文件中。这可能会给下游流程带来问题;-)。。。因此,您需要添加一些代码来清理之前运行的脚本。


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

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

IHTH

最新更新