2012-09-20 132 views
0

我有一个输入文件,如下所示。我需要根据列将它们分成多个文件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)来做到这一点?

+0

我用sort命令和排序基于这3列的文件。 – Anuj

回答

5

是否有可能使用shell脚本(bash)来做到这一点?

如果你只是想分裂基础上的字段2,3档和第5,你可以用awk做到这一点很快:

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

这追加的每一行,以他的名字是由一个文件字段2,3和5

的例子:

[[email protected]]$ awk -F, '{print >> $2"_"$3"_"$5}' infile.txt 
[[email protected]]$ cat Accounts_India_Internal 
12,Accounts,India,free,Internal 
[[email protected]]$ 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

+2

awk出人意料的酷炫。你真的需要排序吗? – TLP

+0

是的。这正是我需要的。谢谢。你能否给我推荐一本关于awk的好书/教程。另外,如果我想在该打印中添加一些条件,该怎么办。比方说,如果我需要创建单独的文件,包括第4列以及第2列是否是HR? – Anuj

+0

@TLP不,排序不是真的需要文件拆分(正在编辑中;))。但是,如果OP想要对最终结果进行排序,则在拆分之前首先对内容进行排序更为容易。 –

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; 
} 
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"; 
} 

为Foo,然后输出

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 
+0

这也适用于我。谢谢。 – Anuj

0

保存输入文本:

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 - '/^$/' {*} 
相关问题