根据主文件重新排列不同版本文本文件的标题和数据

根据主文件重新排列不同版本文本文件的标题和数据

我想在参考主文件中指定的字段|顺序中重新排列多个管道分隔文本文件中的数据(标题和详细信息),并使用 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|

注意:这不仅限于两个输入文件。它可以一次处理任意数量的输入文件。只有两个限制:

  1. 主参考文件(例如master.txt必须是命令行上的第一个参数。

  2. 必须至少有一个输入文件或者输入文件必须通过管道传输到脚本中。

    注意:只能输入一个文件管道式的- 如果通过管道输入多个文件,脚本无法知道哪些行是标题行,哪些行是数据行。

相关内容