【问题标题】:Unix join on more than two filesUnix加入两个以上的文件
【发布时间】:2012-02-09 14:43:09
【问题描述】:

我有三个文件,每个文件都有一个 ID 和一个值。

sdt5z@fir-s:~/test$ ls
a.txt  b.txt  c.txt
sdt5z@fir-s:~/test$ cat a.txt 
id1 1
id2 2
id3 3
sdt5z@fir-s:~/test$ cat b.txt 
id1 4
id2 5
id3 6
sdt5z@fir-s:~/test$ cat c.txt 
id1 7
id2 8
id3 9

我想创建一个看起来像这样的文件...

id1 1 4 7
id2 2 5 8
id3 3 6 9

...最好使用单个命令。

我知道加入和粘贴命令。每次粘贴都会复制 id 列:

sdt5z@fir-s:~/test$ paste a.txt b.txt c.txt 
id1 1   id1 4   id1 7
id2 2   id2 5   id2 8
id3 3   id3 6   id3 9

加入效果很好,但一次只能用于两个文件:

sdt5z@fir-s:~/test$ join a.txt b.txt 
id1 1 4
id2 2 5
id3 3 6
sdt5z@fir-s:~/test$ join a.txt b.txt c.txt 
join: extra operand `c.txt'
Try `join --help' for more information.

我也知道 paste 可以通过使用“-”将 STDIN 作为参数之一。例如,我可以使用以下命令复制连接命令:

sdt5z@fir-s:~/test$ cut -f2 b.txt | paste a.txt -
id1 1   4
id2 2   5
id3 3   6

但我仍然不确定如何修改它以容纳三个文件。

由于我在 perl 脚本中执行此操作,我知道我可以执行类似将其放入 foreach 循环之类的操作,例如 join file1 file2 > tmp1、join tmp1 file3 > tmp2 等。但这会变得混乱,并且我想用单线来做到这一点。

【问题讨论】:

  • 我也知道这是一个带有 SQL 内连接的小菜一碟,但我不想先将所有这些加载到数据库中。

标签: perl text join paste cut


【解决方案1】:

join a.txt b.txt|join - c.txt

应该够了

【讨论】:

  • 或者:join <(join a.txt b.txt) c.txt
  • 这很好用。加入 a b |加入-c |加入 - d ...等。那一个比
【解决方案2】:

既然您是在在 Perl 脚本中进行操作,那么您是否有任何具体原因没有在 Perl 中完成这项工作,而不是在 shell 中生成?

类似的东西(未测试!警告购买者):

use File::Slurp; # Slurp the files in if they aren't too big
my @files = qw(a.txt b.txt c.txt);
my %file_data = map ($_ => [ read_file($_) ] ) @files;
my @id_orders;
my %data = ();
my $first_file = 1;
foreach my $file (@files) {
    foreach my $line (@{ $file_data{$file} }) {
        my ($id, $value) = split(/\s+/, $line);
        push @id_orders, $id if $first_file;
        $data{$id} ||= [];
        push @{ $data{$id} }, $value;
    }
    $first_file = 0;
}
foreach my $id (@id_orders) {
    print "$d " . join(" ", @{ $data{$id} }) . "\n";
}

【讨论】:

  • 这也是我希望能够在命令行中执行的操作。我本质上是使用 perl 将其他人编写的一些其他程序和脚本(python、C++ 等)粘合在一起。 a.txt、b.txt 等是其中一个 python 脚本的输出,我现在需要将它们混合在一起,然后再将它们导入统计程序。
  • @StephenTurner - 只要您不介意支付(不太高的)罚款/生成 shell 进程的成本,当然可以。
【解决方案3】:

perl -lanE'$h{$F[0]} .= " $F[1]" END{say $_.$h{$_} foreach keys %h}' *.txt

应该可以,因为我正在通过手机回答,所以无法对其进行测试。如果您在foreachkeys 之间放置一个sort,您也可以对输出进行排序。

【讨论】:

    【解决方案4】:
    pr -m -t -s\  file1.txt file2.txt|gawk '{print $1"\t"$2"\t"$3"\t"$4}'> finalfile.txt
    

    考虑到 file1 和 file2 有 2 列,1 和 2 代表来自 file1 的列,3 和 4 代表来自 file2 的列。

    您也可以通过这种方式打印每个文件中的任何列,并且它将接受任意数量的文件作为输入。例如,如果您的 file1 有 5 列,则 $6 将是 file2 的第一列。

    【讨论】:

      猜你喜欢
      • 2012-10-27
      • 1970-01-01
      • 2019-04-04
      • 1970-01-01
      • 1970-01-01
      • 2013-06-24
      • 1970-01-01
      • 2017-10-19
      相关资源
      最近更新 更多