여러 파일에서 행과 일치하는 3열의 숫자가 더 높은 행을 검색합니다.

여러 파일에서 행과 일치하는 3열의 숫자가 더 높은 행을 검색합니다.

다음과 유사한 콘텐츠가 포함된 파일이 여러 개 있습니다.

기본 파일 1:

test01:6733:4370:5342
test02:7776:2018:1001
test03:9865:5632:1429
test04:8477:4757:1890
test05:8019:8860:5298
test06:5602:3100:6995
test07:1445:2850:2755
test08:10924:2562:4867
test09:2575:1884:1611

예제 파일 2:

test01:8777:1060:9236
test02:1322:1211:10837
test04:3737:10175:5219
test05:8467:8988:9739
test06:7452:3100:2709
test08:4707:9047:10578
test09:8669:2867:8233
test10:8615:10002:7056

예제 파일 3:

test01:10957:8172:2472
test02:1401:6160:5894
test03:7245:8934:5725
test04:8477:10106:10069
test05:10769:10381:1102
test06:3605:3713:7695
test08:10924:2562:10568
test09:2913:5628:1305
test10:5501:10293:2319

메인 파일 1의 모든 행을 첫 번째 열이 같고 세 번째 열의 모든 파일 중 가장 많은 수를 가진 다른 파일의 행으로 업데이트하고 싶습니다.

기본 파일의 첫 번째 열만 고려해야 합니다(다른 파일에는 있지만 기본 파일에는 없는 test##은 무시해야 함).

다른 파일에서 더 많은 행이 발견되면(세 번째 열의 숫자는 더 크지만 양은 동일함) 그 중 하나를 사용하여 기본 파일을 업데이트할 수 있습니다.

이것은 최적의 솔루션이 아닙니다.

$ awk -F: '{print $1,$3}' main|while read a b;do grep ^${a}: main file*|sort -t":" -rnk4|awk -F: -vb=$b '{if($4>b){print $0;next} else {print ($1=="main")? $0 : NULL}}'|head -1;done
file3:test01:10957:8172:2472
file3:test02:1401:6160:5894
file3:test03:7245:8934:5725
file2:test04:3737:10175:5219
file3:test05:10769:10381:1102
file3:test06:3605:3713:7695
main:test07:1445:2850:2755
file2:test08:4707:9047:10578
file3:test09:2913:5628:1305

awk에서 이러한 모든 파일을 한 번에 처리하고 명령에 while 루프와 많은 파이프 없이 작업을 완료하려면 어떻게 해야 합니까?

업데이트: @RomanPerekhrest, 훌륭한 코드를 제공해 주셔서 감사합니다. 다른 파일의 모든 줄에 :updated 접미사를 어떻게 추가합니까? 나는 다음과 같은 것을 원합니다 :

test01:10957:8172:2472:updated
test02:1401:6160:5894:updated
test03:7245:8934:5725:updated
test04:3737:10175:5219:updated
test05:10769:10381:1102:updated
test06:3605:3713:7695:updated
test07:1445:2850:2755
test08:4707:9047:10578:updated
test09:2913:5628:1305:updated

업데이트: 이전에 예측하지 못했던 새로운 사례가 있습니다. 다른 파일의 $3 값은 더 크지만 $2 열에는 숫자가 없습니다. 이 경우 이와 같은 행($3 더 크지만) 오류 값은 $2이므로 무시해야 합니다.

이를 설명하기 위해 위의 예제 파일을 사용하여 file2의 "test09" 줄에서 두 번째 열을 "xxxxx"로 바꾸었고 이제 다음과 같은 결과가 표시됩니다.

$ grep test09 *
file2:test09:xxxxx:2867:8233
file3:test09:2913:5628:1305
main:test09:2575:1884:1611
$ awk -F':' 'FILENAME != "main"{ if ($2~/^[0-9]+/&&(!($1 in a) || ($3 > a[$1]))) { a[$1]=$3; b[$1]=$0 } next }{ if (($1 in a) && (a[$1] > $3)){ print b[$1]":updated"; delete b[$1] } else print  }' file* main
test01:10957:8172:2472:updated
test02:1401:6160:5894:updated
test03:7245:8934:5725:updated
test04:3737:10175:5219:updated
test05:10769:10381:1102:updated
test06:3605:3713:7695:updated
test07:1445:2850:2755
test08:4707:9047:10578:updated
test09:2913:5628:1305:updated <- this is now update from file3

다음으로, file3의 "test09" 줄에 있는 $2 값도 숫자가 아닌 값으로 변경했습니다.

$ grep test09 *
file2:test09:xxxxx:2867:8233
file3:test09:zzzzz:5628:1305
main:test09:2575:1884:1611
$ awk -F':' 'FILENAME != "main"{ if ($2~/^[0-9]+/&&(!($1 in a) || ($3 > a[$1]))) { a[$1]=$3; b[$1]=$0 } next }{ if (($1 in a) && (a[$1] > $3)){ print b[$1]":updated"; delete b[$1] } else print  }' file* main
test01:10957:8172:2472:updated
test02:1401:6160:5894:updated
test03:7245:8934:5725:updated
test04:3737:10175:5219:updated
test05:10769:10381:1102:updated
test06:3605:3713:7695:updated
test07:1445:2850:2755
test08:4707:9047:10578:updated
test09:2575:1884:1611 <-- this is now from the main file

정상적으로 작동하는 것 같지만 코드의 두 번째 "if"에 대해 설명해 주시겠습니까? 필요한 조건도 있나요 $2~/^[0-9]+/?

{ if (($1 in a) && (a[$1] > $3))

답변1

최적화awk해결책은 대략27몇 배 더 빨라짐:

awk -F':' 'FILENAME != "main"{ 
               if (!($1 in a) || $3 > a[$1]) { a[$1] = $3; b[$1] = $0 } next; 
           }
           { 
               if (($1 in a) && (a[$1] > $3)){ print b[$1]; delete b[$1] } 
               else print; 
           }' file* main

산출:

test01:10957:8172:2472
test02:1401:6160:5894
test03:7245:8934:5725
test04:3737:10175:5219
test05:10769:10381:1102
test06:3605:3713:7695
test07:1445:2850:2755
test08:4707:9047:10578
test09:2913:5628:1305

실행 시간 비교:

$ time(awk -F: '{print $1,$3}' main |while read a b; do grep ^${a}: main file* | sort -t":" -rnk4 | awk -F':' -vb=$b '{if($4>b){print $0;next} else {print ($1=="main")? $0 : NULL}}' | head -1; done > /dev/null)

real    0m0.111s
user    0m0.004s
sys 0m0.012s

$ time(awk -F':' 'FILENAME != "main"{ if (!($1 in a) || $3 > a[$1]) { a[$1]=$3; b[$1]=$0 } next }{ if (($1 in a) && (a[$1] > $3)){ print b[$1]; delete b[$1] } else print  }' file* main > /dev/null)

real    0m0.004s
user    0m0.000s
sys 0m0.000s

관련 정보