我想在参考主文件中指定的字段|顺序中重新排列多个管道分隔文本文件中的数据(标题和详细信息),并使用 shell 脚本创建单个输出文件。我有下面的代码,但没有按预期工作。 while 循环从 master 获取列的顺序,并重新排列。但需要考虑以下功能。在 Shell 脚本/awk 中寻找解决方案。
与参考主文件相比,输入文件中可能存在缺失列或新列。参考主文件中的顺序将来可能会发生变化,并且可以在任何位置添加或删除列。接受多个输入文件。
示例输入文件 A:
Name|Amount|Vehicle|City|Visits|Indicator
Jack|123.22|Volkswagen|Altamonte|1|Y
Sam|23.1|Audi||3|N
|21.4|Ford|NewYork||Y
示例输入文件 B:
Suffix|Name|Visits|Vehicle|State|Indicator|City|Gender
Mr|Jack|1|Volkswagen|NJ|Y|Hoboken|M
Mr|Rob|6|Buick||N|Stamford|
参考主文件:
州|1
城市|2
车辆|3
性别|4
姓名|5
数量|6
输出文件:
State|City|Vehicle|Gender|Name|Amount
|Altamonte|Volkswagen||Jack|123.22
||Audi||Sam|23.1
|NewYork|Ford|||21.4
NJ|Hoboken|Volkswagen|M|Jack|
|Stamford|Buick||Rob|
外壳脚本:
/*Comment::Reads the input column names and assign number based on order for*/
/*Comment::each column in the input file.*/
cat infile.out | head -1 | tr -s '|' '\n' | cat -n > infile_tmp.out
rm -f final.out
/*Comment:compare the master file column names with input file column names and
/*Comment:get the column number from master file*/
while read line; do
touch final.out
vChkClmn=`echo $line | cut -d "|" -f1`
vMasterClm=`grep -i $vChkClmn infile_tmp.out | cut -d " " -f1`
echo "$vMasterClm" >> final.out
done < master_file.out
rm -f final_master_list.out
echo `cat final.out` | sed 's/[^ ]* */\$&/g' | sed 's/ /\,/g' > final_master_list.out
vOrder=`cat final_master_list.out`
echo "Value of order is $vOrder"
awk -F\| '{print '$vOrder'}' OFS=\| infile.out
答案1
#!/usr/bin/perl
use strict;
my $master = shift;
open(M,"<","$master") || die "couldn't open $master:$!\n";
chomp(my @master = split(/\|/,<M>));
close(M);
print join("|",@master),"\n";
my @fields=();
while (<>) {
if ($. == 1) {
chomp(@fields = split /\|/);
next;
};
chomp(my @row = split/\|/);
my @out = ();
foreach my $m (@master) {
my $o='';
for (my $i=0; $i < $#row; $i++) {
if ($fields[$i] eq $m) {
$o = $row[$i];
};
}
push @out, $o;
};
print join("|",@out),"\n";
} continue {
close ARGV if eof; # reset the line counter after each input file
}
这会读入参考主文件(其中必须是命令行上的第一个参数)并将其拆分为保存字段名称的数组(@master)。
之后,它读取所有剩余的文件名参数并:
- 如果是文件的第一行,则通过将该行拆分为数组来获取字段标题
@fields
- 否则,将该行拆分为 array
@row
,并循环遍历 @master 和 的每个元素@row
。当场姓名行元素的一个与 @master 中的元素匹配,添加该字段的价值到输出数组 (@out),否则添加空字符串。 - 打印
@out
由字符连接的数组|
。 - 该
@out
数组在每个输入行上都重置为空。
将其另存为,例如,rearrange.pl
使其可执行chmod +x rearrange.pl
并运行为:
$ ./rearrange.pl master.txt input1.txt input2.txt
State|City|Vehicle|Gender|Name|Amount
|Altamonte|Volkswagen||Jack|123.22
||Audi||Sam|23.1
|NewYork|Ford|||21.4
NJ|Hoboken|Volkswagen||Jack|
|Stamford|Buick||Rob|
注意:这不仅限于两个输入文件。它可以一次处理任意数量的输入文件。只有两个限制:
主参考文件(例如
master.txt
)必须是命令行上的第一个参数。必须至少有一个输入文件或者输入文件必须通过管道传输到脚本中。
注意:只能输入一个文件管道式的- 如果通过管道输入多个文件,脚本无法知道哪些行是标题行,哪些行是数据行。