awkを使用してxargsを介したパイピングを使用した文字列の列のフィルタリング

awkを使用してxargsを介したパイピングを使用した文字列の列のフィルタリング

いくつかのファイルがあります。

file1.csv
file2.csv
file3.csv

与えられたスクリプトはそれを処理し、次のファイルに書き込みます。

my.log

次の形式を取ります。(filename col2 col3):

file1.csv 1 a
file2.csv 1 a
file3.csv 1 a
file2.csv 2 b
file1.csv 2 b
file3.csv 2 b
file1.csv 3 c
file2.csv 3 c
file3.csv 3 c
file2.csv 4 d
file3.csv 4 d

col3各ファイル(最後のファイルのみ)ごとにファイルから値を取得したいと思います。my.log*.csv

次のコマンドを実行します。

ls *.csv | xargs -I@ bash -c "cat my.log | grep @ | tail -n 1 | awk '{ print $3 }'"

awkが私にすべての熱を与えることを除いて、うまくいきます。

file1.csv 3 c
file2.csv 4 d
file3.csv 4 d

列を1つだけ取得するにはどうすればよいですかcol3?たとえば、次のようになります。

c
d
d

答え1

あなたの表現に

 "cat my.log | grep @ | tail -n 1 | awk '{ print $3 }'"

...文字列の周囲の二重引用符は、一重引用符がリテラルとして処理されることを意味します。シェルを保護しないので、$3環境変数に展開されます。実際にはシェルによって定義されていないので$3(3つの引数で呼び出すスクリプトにない限り)空の文字列になり、式はawk単に{ print }行全体を印刷します。

以下をエスケープしてこの問題を解決できます$

ls *.csv | xargs -I@ bash -c "cat my.log | grep @|tail -n 1|awk '{print \$3}'"

...または式をawk外に移動してxargs

ls *.csv | xargs -I@ bash -c "cat my.log | grep @|tail -n 1"|awk '{print $3}'

答え2

ls単にターミナルで見る以外に into の出力をパイプで接続するのは良くありませんxargs(実際、 into の出力で何でもするのは良いことではありません )。ls悪い考え)。必ずこのような作業を行う必要がある場合は、少なくともそのような作業を使用してfind . -maxdepth 1 -type f -iname '*.csv' -print0くださいxargs -0r

ただし、この場合、.csvファイルのファイル名は次のようになるため、まったくそうする必要はありません。すでにここにmy.log

まったく:

#!/usr/bin/awk -f

{ seen[$1] = $3 }

END {
  for (f in seen) { print seen[f] };
}

または1行で:

$ awk '{seen[$1] = $3}; END {for (f in seen) { print seen[f] };}' my.log 
c
d
d

これにより、列 1 にリストされた各ファイルについて、列 3 に示された最後の値が印刷されます。

列3に示されている最初の値のみを印刷するには、次のように変更します。

!seen[$1] { seen[$1] = $3 }

現在のディレクトリにあるすべてのファイルのファイル名を使用したくなく、find | xargs実際に使用する必要がある場合は、代わりに次のようにします。.csv

#!/usr/bin/perl

use strict;

my $logfile=shift;      # get the first arg (the logfile name)

my $re=join("|",@ARGV); # turn the remaining args into a regular expression

@ARGV=$logfile;         # set the logfile name as the sole cmd-line argument.

my %seen=();

while(<>) {
   next unless (m/^($re)/o); # ignore any filenames that weren't on the cmd line.
   my(@F) = split;
   $seen{$F[0]} = $F[2];  # perl arrays start from 0, not 1.
};

foreach my $file (sort keys %seen) {
  print $seen{$file}, "\n";
};

たとえば、別の名前で保存してnandro.pl実行可能にしたら、chmod +x次のように実行します。

$ ./nandro.pl my.log *.csv
c
d
d

関連情報