0

次のような入力ファイルがあります。列 2、3、および 5 に基づいて複数のファイルに分割する必要があります。ファイルにはさらに列がありますが、カットコマンドを使用して必要な列のみを取得しました。

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) に基づいてファイルを並べ替え、各レコードでループを実行してファイルの作成を開始することを考えています。ファイルが存在しない場合は、レコードを作成して追加します。それ以外の場合は、古いファイルを開いてレコードを追加してください。

シェルスクリプト (bash) を使用してこれを行うことは可能ですか?

4

4 に答える 4

5

シェルスクリプト (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

ファイルに追加しているので、出力ファイルを削除せずにコマンドを繰り返すと、出力ファイルに重複データが含まれることになることに注意してください。これに対処し、チャットで述べたように追加の要件 (すべての新しいファイルのヘッダーとして最初の行を使用) を含めるには、このソリューションを参照してください。

于 2012-09-20T15:20:50.293 に答える
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
于 2012-09-20T15:27:13.297 に答える
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;
}
于 2012-09-20T15:26:41.277 に答える
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 - '/^$/' {*}
于 2012-09-20T15:30:31.047 に答える