根据列连接将大文件拆分为小的多个文件

时间:2012-09-20 15:10:35

标签: perl shell

我有一个输入文件如下。我需要根据2,3和5列将它们分成多个文件。该文件有更多列,但我使用cut命令只获取所需的列。

12,Accounts,India,free,Internal
13,Finance,China,used,Internal
16,Finance,China,free,Internal
12,HR,India,free,External
19,HR,China,used,Internal
33,Finance,Japan,free,Internal
39,Accounts,US,used,External
14,Accounts,Japan,used,External
11,Finance,India,used,External
11,HR,US,used,External
10,HR,India,used,External

输出文件:

Accounts_India_Internal --
12,Accounts,India,free,Internal

Finance_China_Internal --
13,Finance,China,used,Internal
16,Finance,China,free,Internal

HR_India_External --
12,HR,India,free,External
10,HR,India,used,External

HR_China_Internal --
19,HR,China,used,Internal

依旧......

请告诉我如何实现这一目标。

截至目前,我正在考虑根据这些列(2,3,5)对文件进行排序,然后在每条记录上运行循环并开始创建文件。如果文件不存在,则创建并添加记录。否则打开旧文件并添加记录。

是否可以使用shell脚本(bash)执行此操作?

4 个答案:

答案 0 :(得分:5)

  

是否可以使用shell脚本(bash)执行此操作?

如果您只是想根据字段2,3和5拆分文件,可以使用awk快速完成:

awk -F, '{print >> $2"_"$3"_"$5}' infile.txt 

将每行附加到名称由字段2,3和5组成的文件中。

示例:

[me@home]$ awk -F, '{print >> $2"_"$3"_"$5}' infile.txt 
[me@home]$ cat Accounts_India_Internal
12,Accounts,India,free,Internal
[me@home]$ cat Finance_China_Internal
13,Finance,China,used,Internal
16,Finance,China,free,Internal

如果您确实希望输出排序,则可以先通过sort运行该文件。

sort -k2,3 -k5,5 -t, infile.txt  | awk -F, '{print >> $2"_"$3"_"$5}'

在将字段2,3和5传递给awk命令之前对其进行排序。

请注意我们附加到文件,因此如果重复命令而不删除输出文件,则最终会在输出文件中出现重复数据。要解决此问题,并在the chat中提及您的附加要求(使用第一行作为所有新文件的标题),请参阅this solution

答案 1 :(得分:1)

我建议你保留一个由相应文件名键入的文件句柄哈希

该程序演示。输入文件需要作为命令行上的参数

use strict;
use warnings;

my %fh;

while (<>) {
  chomp;
  my $filename = join '_', (split /,/)[1,2,4];
  if (not $fh{$filename}) {
    open $fh{$filename}, '>', $filename or die "Unable to open '$filename' for output: $!";
    print "$filename created\n";
  }
  print { $fh{$filename} } $_, "\n";
}

<强>输出

Accounts_India_Internal created
Finance_China_Internal created
HR_India_External created
HR_China_Internal created
Finance_Japan_Internal created
Accounts_US_External created
Accounts_Japan_External created
Finance_India_External created
HR_US_External created

答案 2 :(得分:0)

注意:要使用代码,只需将<DATA>更改为<>并使用文件名作为参数。 Data::Dumper打印仅用于演示目的,也可以删除。

use strict;
use warnings;
use Data::Dumper;

my %h;
while (<DATA>) {
    chomp;
    my @data = split /,/;
    my $file = join "_", @data[1,2,4];
    push @{$h{$file}}, $_;
}
print Dumper \%h;

__DATA__
12,Accounts,India,free,Internal
13,Finance,China,used,Internal
16,Finance,China,free,Internal
12,HR,India,free,External
19,HR,China,used,Internal
33,Finance,Japan,free,Internal
39,Accounts,US,used,External
14,Accounts,Japan,used,External
11,Finance,India,used,External
11,HR,US,used,External
10,HR,India,used,External

要打印文件,您可以使用如下子程序:

for my $key (keys %h) {
    print_file($key, $h{$key};
}
sub print_file {
    my ($file, $data) = @_;
    open my $fh, ">", $file or die $!;
    print $fh "$_\n" for @$data;
}

答案 3 :(得分:0)

将输入文本保存为foo,然后:

cat foo | perl -nle '$k = join "_", (split ",", $_)[1,2,4]; $t{$k} = [@{$t{$k}}, $_]; END{for (keys %t){print join "\n", "$_ --", @{$t{$_}}, undef }}' | csplit -sz - '/^$/' {*}