다음과 유사한 콘텐츠가 포함된 파일이 여러 개 있습니다.
기본 파일 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