如何通过awk从一个文件中并排列的多个文件中输出数据?
how to output data from multiple files in side by side columns in one file via awk?
我有 30 个文件,名为 UE1.dat、UE2.dat .... 每个文件有 4 列。下面给出了 UE1.dat 和 UE2.dat.
的列结构示例
UE1.dat
1 4 2 1
2 2 3 3
3 2 4 4
4 4 4 2
UE2.dat
2 6 8 7
4 4 9 6
7 1 1 2
9 3 3 3
所以,我尝试了以下代码:
for((i=1;i<=30;i++)); do awk 'NR$i {printf ",";next} 1; END {print ""}' UE$i.dat; done > UE_all.dat
只从每个文件中获取第一列并将它们写入单个文件和并排的列,下面给出了所需的输出。
1 2
2 4
3 7
4 9
但不幸的是,代码将它们按行排序,你能给个提示吗?
提前致谢!
我可能会选择 - 使用 perl
而不是 awk
,因为我更喜欢数据结构的处理。在这种情况下 - 我们使用二维数组,将每个文件的第一列插入到数组的新列中,然后打印整个内容。
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
my $num_files = 2;
my @rows;
my $count = 0;
my $max = 0;
for my $filenum ( 1..$num_files ) {
open ( my $input, "<", "UE${filenum}.dat" ) or die $!;
while ( <$input> ) {
my @fields = split;
push ( @{$rows[$filenum]}, $fields[0] );
$count++;
}
close ( $input );
if ( $count > $max ) { $max = $count };
}
print Dumper \@rows;
for ( 0..$count ) {
foreach my $filenum ( 1..$num_files ) {
print shift @{$rows[$filenum]} || ''," ";
}
print "\n";
}
在 awk 中你可以这样做:
1) 将此代码放入名为 output_data_from_multiple_files.awk
:
的文件中
BEGIN {
# All the input files are processed in one run.
# filenumber counts the number of input files.
filenumber = 1
}
{
# FNR is the input record number in the current input file.
# Concatenate the value of the first column in the corresponding
# line in the output.
output[FNR] = output[FNR] " "
# FNR == 1 means we are processing a new file.
if (FNR == 1) {
++filenumber
}
}
END {
# print the output
for (i=1; i<=FNR; i++)
printf("%s\n", output[i])
}
2) 运行 awk -f output_data_from_multiple_files.awk UE*
所有文件都在 awk
的单次执行中处理。 FNR
为当前输入文件中的输入记录号。 filenumber
用于统计处理的文件数。输入文件中读取的值连接在 output
数组中。
我的解决方案是这样的
gawk 'BEGINFILE{f++}{print FNR,f,}' UE* | sort -nk 1,2 | cut -d" " -f3 | xargs -L $(ls UE*.dat | wc -l)
这就是我的方法...我使用 gawk
对行和文件进行编号,然后按行号对它们进行排序,然后按文件排序,只需使用 sort
并删除文件和行号。所以...
gawk 'BEGINFILE{f++}{print FNR,f,}' UE*
1 1 1 # line 1 file 1 is 1
2 1 2 # line 2 file 1 is 2
3 1 3 # line 3 file 1 is 3
4 1 4 # line 4 file 1 is 4
1 2 2 # line 1 file 2 is 2
2 2 4 # line 2 file 2 is 4
3 2 7 # line 3 file 2 is 7
4 2 9 # line 4 file 2 is 9
然后像这样使用sort
把文件1的第一行接着文件2的第一行,文件n的第一行,文件1的第二行,文件2的第二行,第二个文件行 n。然后得到第三列:
gawk 'BEGINFILE{f++}{print FNR,f,}' UE* | sort -nk 1,2 | cut -d" " -f3
1
2
2
4
3
7
4
9
然后和xargs
一起放回去
gawk 'BEGINFILE{f++}{print FNR,f,}' UE* | sort -nk 1,2 | cut -d" " -f3 | xargs -L2
1 2
2 4
3 7
4 9
末尾的 -L2
必须与文件数匹配,即您的 -L30
。
使用 awk
关联数组将所有列连接到一个文件中:
# use a wildcard to get all the files (could also use a for-loop)
# add each new row to the array using line number as an index
# at the end of reading all files, go through each index (will be 1-4 in
# your example) and print index, and then the fully concatenated rows
awk '{a[FNR] = a[FNR]" "[=10=]}END{ for (i in a) print i, a[i] | "sort -k1n"}' allfiles*
我有 30 个文件,名为 UE1.dat、UE2.dat .... 每个文件有 4 列。下面给出了 UE1.dat 和 UE2.dat.
的列结构示例UE1.dat
1 4 2 1
2 2 3 3
3 2 4 4
4 4 4 2
UE2.dat
2 6 8 7
4 4 9 6
7 1 1 2
9 3 3 3
所以,我尝试了以下代码:
for((i=1;i<=30;i++)); do awk 'NR$i {printf ",";next} 1; END {print ""}' UE$i.dat; done > UE_all.dat
只从每个文件中获取第一列并将它们写入单个文件和并排的列,下面给出了所需的输出。
1 2
2 4
3 7
4 9
但不幸的是,代码将它们按行排序,你能给个提示吗?
提前致谢!
我可能会选择 - 使用 perl
而不是 awk
,因为我更喜欢数据结构的处理。在这种情况下 - 我们使用二维数组,将每个文件的第一列插入到数组的新列中,然后打印整个内容。
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
my $num_files = 2;
my @rows;
my $count = 0;
my $max = 0;
for my $filenum ( 1..$num_files ) {
open ( my $input, "<", "UE${filenum}.dat" ) or die $!;
while ( <$input> ) {
my @fields = split;
push ( @{$rows[$filenum]}, $fields[0] );
$count++;
}
close ( $input );
if ( $count > $max ) { $max = $count };
}
print Dumper \@rows;
for ( 0..$count ) {
foreach my $filenum ( 1..$num_files ) {
print shift @{$rows[$filenum]} || ''," ";
}
print "\n";
}
在 awk 中你可以这样做:
1) 将此代码放入名为 output_data_from_multiple_files.awk
:
BEGIN {
# All the input files are processed in one run.
# filenumber counts the number of input files.
filenumber = 1
}
{
# FNR is the input record number in the current input file.
# Concatenate the value of the first column in the corresponding
# line in the output.
output[FNR] = output[FNR] " "
# FNR == 1 means we are processing a new file.
if (FNR == 1) {
++filenumber
}
}
END {
# print the output
for (i=1; i<=FNR; i++)
printf("%s\n", output[i])
}
2) 运行 awk -f output_data_from_multiple_files.awk UE*
所有文件都在 awk
的单次执行中处理。 FNR
为当前输入文件中的输入记录号。 filenumber
用于统计处理的文件数。输入文件中读取的值连接在 output
数组中。
我的解决方案是这样的
gawk 'BEGINFILE{f++}{print FNR,f,}' UE* | sort -nk 1,2 | cut -d" " -f3 | xargs -L $(ls UE*.dat | wc -l)
这就是我的方法...我使用 gawk
对行和文件进行编号,然后按行号对它们进行排序,然后按文件排序,只需使用 sort
并删除文件和行号。所以...
gawk 'BEGINFILE{f++}{print FNR,f,}' UE*
1 1 1 # line 1 file 1 is 1
2 1 2 # line 2 file 1 is 2
3 1 3 # line 3 file 1 is 3
4 1 4 # line 4 file 1 is 4
1 2 2 # line 1 file 2 is 2
2 2 4 # line 2 file 2 is 4
3 2 7 # line 3 file 2 is 7
4 2 9 # line 4 file 2 is 9
然后像这样使用sort
把文件1的第一行接着文件2的第一行,文件n的第一行,文件1的第二行,文件2的第二行,第二个文件行 n。然后得到第三列:
gawk 'BEGINFILE{f++}{print FNR,f,}' UE* | sort -nk 1,2 | cut -d" " -f3
1
2
2
4
3
7
4
9
然后和xargs
gawk 'BEGINFILE{f++}{print FNR,f,}' UE* | sort -nk 1,2 | cut -d" " -f3 | xargs -L2
1 2
2 4
3 7
4 9
末尾的 -L2
必须与文件数匹配,即您的 -L30
。
使用 awk
关联数组将所有列连接到一个文件中:
# use a wildcard to get all the files (could also use a for-loop)
# add each new row to the array using line number as an index
# at the end of reading all files, go through each index (will be 1-4 in
# your example) and print index, and then the fully concatenated rows
awk '{a[FNR] = a[FNR]" "[=10=]}END{ for (i in a) print i, a[i] | "sort -k1n"}' allfiles*