我在 Linux 上的文件中有一个很大的制表符分隔矩阵:
Name ID ABC12 ABCD12 ABCD123 ABCD1234
ABC12 123456 XX YY ZZ JJ
ABC12 123456 XX YY ZZ JJ
ABCD12 123456 XX YY ZZ JJ
ABCD12 123456 XX YY ZZ JJ
ABCD123 123456 XX YY ZZ JJ
ABCD123 123456 XX YY ZZ JJ
ABCD1234 123456 XX YY ZZ JJ
ABCD1234 123456 XX YY ZZ JJ
我想根据第一列中的匹配将此矩阵拆分为单独的文件,[这是一个大文件,无法计算列数]
预期输出:
文件1;
Name ID ABC12
ABC12 123456 XX
ABC12 123456 XX
文件2;
Name ID ABCD12
ABCD12 123456 YY
ABCD12 123456 YY
文件3;
Name ID ABCD123
ABCD123 123456 ZZ
ABCD123 123456 ZZ
文件4;
Name ID ABCD1234
ABCD1234 123456 JJ
ABCD1234 123456 JJ
答案1
完全的awk解决方案:
awk 'NR==1{ len=split($0,a_pos); for(i=1;i<=len;i++) a_keys[a_pos[i]]=i }
NR>1{ if(!r[$1]++) { fn="file"++c; print "Name\tID\t"$1 > fn }
print $1,$2,$(a_keys[$1]) > fn
}' OFS='\t' file
len=split($0,a_pos)
- 将第一行拆分为“键”数组(数组a_pos
用整数索引)for(i=1;i<=len;i++) a_keys[a_pos[i]]=i
- 翻转到将使用字符串键索引的a_pos
数组(用于进一步处理)a_keys
fn="file"++c
- 构造文件名
查看结果:
for f in file[0-9]*; do (echo "$f"; cat "$f"; echo); done
输出(file1
、file2
、file3
和file4
连续):
file1
Name ID ABC12
ABC12 123456 XX
ABC12 123456 XX
file2
Name ID ABCD12
ABCD12 123456 YY
ABCD12 123456 YY
file3
Name ID ABCD123
ABCD123 123456 ZZ
ABCD123 123456 ZZ
file4
Name ID ABCD1234
ABCD1234 123456 JJ
ABCD1234 123456 JJ
答案2
你可以使用awk
:
awk 'NR>1{if ($1!=p){N="file"++C; print "Name\tID\t"$1 >N};
print $1,$2,$(C+2)>N}{p=$1}' infile.txt
答案3
我能想到的最简单的方法是将第一行保存为变量,然后根据需要打印其余部分。然而,这需要将整个输入文件保存到内存中:
#!/bin/gawk -f
{
if(NR==1){
header[1]=$1;
header[2]=$2;
for(i=3;i<=NF;i++){
header[$i]=i;
}
}
else{
data[$1][NR]=$2"\t"$(header[$1]);
}
}
END{
OFS="\t";
for(i in data){
print header[1],header[2],i > i".txt"
for(k in data[i]){
print i,data[i][k] >> i".txt"
}
}
}
将该脚本另存为foo.awk
,使其可执行 ( chmod a+x foo.awk
) 并在您的文件上运行它:
foo.awk file
答案4
用法: ./split_matrix.awk input.txt
#!/usr/bin/awk -f
BEGIN {
cnt = 1;
}
NR == 1 {
for(i = 3; i <= NF; i++) {
headers[$i] = i;
}
}
NR > 1 {
if( ! file_names[$1]) {
file_names[$1] = cnt++;
printf "%s %s %s\n", "Name", "ID", $1 > "file_"file_names[$1];
}
printf "%s %s %s\n", $1, $2, $headers[$1] >> "file_"file_names[$1];
}
测试
输入
Name ID ABC12 ABCD12 ABCD123 ABCD1234
ABC12 123456 XX YY ZZ JJ
ABC12 123456 XX YY ZZ JJ
ABCD12 123456 XX YY ZZ JJ
ABCD12 123456 XX YY ZZ JJ
ABCD123 123456 XX YY ZZ JJ
ABCD123 123456 XX YY ZZ JJ
ABCD1234 123456 XX YY ZZ JJ
ABCD1234 123456 XX YY ZZ JJ
输出(用于tail -n +1 -- file*
打印文件名和文件内容。我发现了这个技巧这里)
==> file_1 <==
Name ID ABC12
ABC12 123456 XX
ABC12 123456 XX
==> file_2 <==
Name ID ABCD12
ABCD12 123456 YY
ABCD12 123456 YY
==> file_3 <==
Name ID ABCD123
ABCD123 123456 ZZ
ABCD123 123456 ZZ
==> file_4 <==
Name ID ABCD1234
ABCD1234 123456 JJ
ABCD1234 123456 JJ