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

열을 하나만 얻으려면 어떻게 해야 합니까 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] };
}

또는 한 줄로:

$ 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

관련 정보