使用 AWK 组织文件
Organize a file with AWK
嗯,我有以下文件:
Progeny Sire Dam Sex PENAS P35 P41
13254 11908 11421 M 47.275811 1322.828674 1719.183748
13323 11335 11386 M 43.29896 1225.57111 1634.436447
13562 11864 11895 M 47.884191 1228.568357 1615.427502
13338 11335 11970 M 45.780973 1196.32757 1561.900145
我需要转置 PENAS、P35 和 P41 列。这些列将成为新列:年龄。在视觉上,我需要这样的文件:
Progeny Sire Dam Sex AGE Peso
13254 11908 11421 M PENAS 47.275811
13254 11908 11421 M P35 1322.828674
13254 11908 11421 M P41 1719.183748
13323 11335 11386 M PENAS 43.29896
13323 11335 11386 M P35 1225.57111
13323 11335 11386 M P41 1634.436447
13562 11864 11895 M PENAS 47.884191
13562 11864 11895 M P35 1228.568357
13562 11864 11895 M P41 1615.427502
13338 11335 11970 M PENAS 45.780973
13338 11335 11970 M P35 1196.32757
13338 11335 11970 M P41 1561.900145
我试过这个命令,但没有用:
awk 'NR==1{h= OFS OFS OFS OFS OFS OFS ; next}
{a[]=(( in a)?(a[] OFS $NF):(OFS OFS OFS OFS "AGE"));
if(!( in b)) {h=h OFS ; b[]}}
END{print h; for(k in a) print k,a[k]}' a.txt | column -t > b
我就卡在这一点上了,有什么建议吗?谢谢。
注意,我的原始数据集有 1400 行。
我会这样做:
transpose.awk
NR == 1 {
NF -= 2 # Remove last two header columns
$NF = "AGE" # Add AGE column header
$(NF+1) = "Peso" # Add Peso column header
print # Print header
next # Skip to next line
}
{
for (i=5; i<=7; i++) {
if(i==5) s = "PENAS"
if(i==6) s = "P35"
if(i==7) s = "P41"
print , , , , s, $i
}
}
运行 例如这样:
awk -v OFS='\t' -f transpose.awk infile
输出:
Progeny Sire Dam Sex AGE Peso
13254 11908 11421 M PENAS 47.275811
13254 11908 11421 M P35 1322.828674
13254 11908 11421 M P41 1719.183748
13323 11335 11386 M PENAS 43.29896
13323 11335 11386 M P35 1225.57111
13323 11335 11386 M P41 1634.436447
13562 11864 11895 M PENAS 47.884191
13562 11864 11895 M P35 1228.568357
13562 11864 11895 M P41 1615.427502
13338 11335 11970 M PENAS 45.780973
13338 11335 11970 M P35 1196.32757
13338 11335 11970 M P41 1561.900145
警告
请注意 EdMorton 评论中关于乱用 NF
的警告。
这是另一个 awk
,不依赖于列数...
$ awk 'NR==1{n=split([=10=],h);
for(i=1;i<=NF-3;i++) printf "%s", $i OFS;
printf "%s\n", "AGE" OFS "Peso"; next}
{split([=10=],p);
NF--;
for(i=1;i<=3;i++)
{$(NF-1)=h[NF-2+i];
$NF=p[NF-2+i];
print}}' file | column -t
Progeny Sire Dam Sex AGE Peso
13254 11908 11421 M PENAS 47.275811
13254 11908 11421 M P35 1322.828674
13254 11908 11421 M P41 1719.183748
13323 11335 11386 M PENAS 43.29896
13323 11335 11386 M P35 1225.57111
13323 11335 11386 M P41 1634.436447
13562 11864 11895 M PENAS 47.884191
13562 11864 11895 M P35 1228.568357
13562 11864 11895 M P41 1615.427502
13338 11335 11970 M PENAS 45.780973
13338 11335 11970 M P35 1196.32757
13338 11335 11970 M P41 1561.900145
以下 awk
也可能对您有所帮助。
awk '
FNR==1{
for(i=5;i<=NF;i++){
a[++h]=$i};
NF-=2;
$NF="AGE Peso";
print;
next}
{
for(j=5;j<=NF;j++){
printf("%s %s %s %s %s %s\n",,,,,a[++k],$j);
k=j==NF?k="":k}
}' Input_file | column -t
使用 GNU awk for gensub():
$ cat tst.awk
BEGIN { numPfx=4 }
{ pfx = gensub("((\S+\s+){"numPfx"}).*","\1",1) }
NR==1 {
split([=10=],ages)
print pfx, "AGE", "Peso"
next
}
{
for (i=numPfx+1; i<=NF; i++) {
print pfx, ages[i], $i
}
}
$ awk -f tst.awk file | column -t
Progeny Sire Dam Sex AGE Peso
13254 11908 11421 M PENAS 47.275811
13254 11908 11421 M P35 1322.828674
13254 11908 11421 M P41 1719.183748
13323 11335 11386 M PENAS 43.29896
13323 11335 11386 M P35 1225.57111
13323 11335 11386 M P41 1634.436447
13562 11864 11895 M PENAS 47.884191
13562 11864 11895 M P35 1228.568357
13562 11864 11895 M P41 1615.427502
13338 11335 11970 M PENAS 45.780973
13338 11335 11970 M P35 1196.32757
13338 11335 11970 M P41 1561.900145
对于其他 awk,您只需将 gensub() 替换为变量加 sub(),将 \S
替换为 [^[:space:]]
,将 \s
替换为 [[:space:]]
。
嗯,我有以下文件:
Progeny Sire Dam Sex PENAS P35 P41
13254 11908 11421 M 47.275811 1322.828674 1719.183748
13323 11335 11386 M 43.29896 1225.57111 1634.436447
13562 11864 11895 M 47.884191 1228.568357 1615.427502
13338 11335 11970 M 45.780973 1196.32757 1561.900145
我需要转置 PENAS、P35 和 P41 列。这些列将成为新列:年龄。在视觉上,我需要这样的文件:
Progeny Sire Dam Sex AGE Peso
13254 11908 11421 M PENAS 47.275811
13254 11908 11421 M P35 1322.828674
13254 11908 11421 M P41 1719.183748
13323 11335 11386 M PENAS 43.29896
13323 11335 11386 M P35 1225.57111
13323 11335 11386 M P41 1634.436447
13562 11864 11895 M PENAS 47.884191
13562 11864 11895 M P35 1228.568357
13562 11864 11895 M P41 1615.427502
13338 11335 11970 M PENAS 45.780973
13338 11335 11970 M P35 1196.32757
13338 11335 11970 M P41 1561.900145
我试过这个命令,但没有用:
awk 'NR==1{h= OFS OFS OFS OFS OFS OFS ; next}
{a[]=(( in a)?(a[] OFS $NF):(OFS OFS OFS OFS "AGE"));
if(!( in b)) {h=h OFS ; b[]}}
END{print h; for(k in a) print k,a[k]}' a.txt | column -t > b
我就卡在这一点上了,有什么建议吗?谢谢。 注意,我的原始数据集有 1400 行。
我会这样做:
transpose.awk
NR == 1 {
NF -= 2 # Remove last two header columns
$NF = "AGE" # Add AGE column header
$(NF+1) = "Peso" # Add Peso column header
print # Print header
next # Skip to next line
}
{
for (i=5; i<=7; i++) {
if(i==5) s = "PENAS"
if(i==6) s = "P35"
if(i==7) s = "P41"
print , , , , s, $i
}
}
运行 例如这样:
awk -v OFS='\t' -f transpose.awk infile
输出:
Progeny Sire Dam Sex AGE Peso
13254 11908 11421 M PENAS 47.275811
13254 11908 11421 M P35 1322.828674
13254 11908 11421 M P41 1719.183748
13323 11335 11386 M PENAS 43.29896
13323 11335 11386 M P35 1225.57111
13323 11335 11386 M P41 1634.436447
13562 11864 11895 M PENAS 47.884191
13562 11864 11895 M P35 1228.568357
13562 11864 11895 M P41 1615.427502
13338 11335 11970 M PENAS 45.780973
13338 11335 11970 M P35 1196.32757
13338 11335 11970 M P41 1561.900145
警告
请注意 EdMorton 评论中关于乱用 NF
的警告。
这是另一个 awk
,不依赖于列数...
$ awk 'NR==1{n=split([=10=],h);
for(i=1;i<=NF-3;i++) printf "%s", $i OFS;
printf "%s\n", "AGE" OFS "Peso"; next}
{split([=10=],p);
NF--;
for(i=1;i<=3;i++)
{$(NF-1)=h[NF-2+i];
$NF=p[NF-2+i];
print}}' file | column -t
Progeny Sire Dam Sex AGE Peso
13254 11908 11421 M PENAS 47.275811
13254 11908 11421 M P35 1322.828674
13254 11908 11421 M P41 1719.183748
13323 11335 11386 M PENAS 43.29896
13323 11335 11386 M P35 1225.57111
13323 11335 11386 M P41 1634.436447
13562 11864 11895 M PENAS 47.884191
13562 11864 11895 M P35 1228.568357
13562 11864 11895 M P41 1615.427502
13338 11335 11970 M PENAS 45.780973
13338 11335 11970 M P35 1196.32757
13338 11335 11970 M P41 1561.900145
以下 awk
也可能对您有所帮助。
awk '
FNR==1{
for(i=5;i<=NF;i++){
a[++h]=$i};
NF-=2;
$NF="AGE Peso";
print;
next}
{
for(j=5;j<=NF;j++){
printf("%s %s %s %s %s %s\n",,,,,a[++k],$j);
k=j==NF?k="":k}
}' Input_file | column -t
使用 GNU awk for gensub():
$ cat tst.awk
BEGIN { numPfx=4 }
{ pfx = gensub("((\S+\s+){"numPfx"}).*","\1",1) }
NR==1 {
split([=10=],ages)
print pfx, "AGE", "Peso"
next
}
{
for (i=numPfx+1; i<=NF; i++) {
print pfx, ages[i], $i
}
}
$ awk -f tst.awk file | column -t
Progeny Sire Dam Sex AGE Peso
13254 11908 11421 M PENAS 47.275811
13254 11908 11421 M P35 1322.828674
13254 11908 11421 M P41 1719.183748
13323 11335 11386 M PENAS 43.29896
13323 11335 11386 M P35 1225.57111
13323 11335 11386 M P41 1634.436447
13562 11864 11895 M PENAS 47.884191
13562 11864 11895 M P35 1228.568357
13562 11864 11895 M P41 1615.427502
13338 11335 11970 M PENAS 45.780973
13338 11335 11970 M P35 1196.32757
13338 11335 11970 M P41 1561.900145
对于其他 awk,您只需将 gensub() 替换为变量加 sub(),将 \S
替换为 [^[:space:]]
,将 \s
替换为 [[:space:]]
。