Bash 스크립트에서 cat 및 xargs 성능을 향상시키는 방법

Bash 스크립트에서 cat 및 xargs 성능을 향상시키는 방법

다음을 호출하여 100만 개의 필드 라인이 포함된 파일을 처리해야 합니다.

1m.txt

이제 내 스크립트는 1m.txt에 포함된 줄의 유효성을 검사합니다.

cat out.txt > advance.txt 2> /dev/null
cat 1m.txt | xargs -I {} -P 100 sh -c "if ! grep --quiet {} advance.txt; then if host {} >/dev/null; then echo OK {}; else echo DIE {}; fi; fi" >> out.txt

이 스크립트가 하는 일은 중단(ctrl+c)되었다가 다시 시작되면 처리된 마지막 줄부터 시작된다는 것입니다. 행이 1,000개라면 200개 행에서 중단된 프로세스가 빠르게 다시 시작됩니다. 그러나 100만 행의 경우 500,000행에 대한 프로세스를 중단하는 데 몇 시간이 걸립니다.

좀 더 효율적으로 만들 수 있는 방법이 있나요?

답변1

따라서 현재 논리는 "1m.txt의 각 행에 대해 이미 advance.txt가 있는지 확인하십시오. 그렇지 않은 경우 이를 처리하여 out.txt에 추가하십시오. 작업이 시작되면 advance.txt가 있는 모든 행으로 업데이트하십시오. out.txt'.

문제는 advance.txt에 더 많은 행이 추가될수록 각각을 비교해야 하는 행이 더 많아진다는 것입니다. 최악의 시나리오는 모든 줄이 처리되는 경우 1m.txt의 백만 줄을 모두 확인하여 advance.txt인지 확인해야 합니다. 평균적으로 advance.txt 행의 절반을 비교해야 하므로 1,000,000*500,000 또는 500,000,000,000(5000억) 번의 비교가 필요합니다.

병렬로 처리하지 않는 경우 이를 처리하는 간단한 방법은 out.txt에서 마지막 줄을 찾아 1m.txt에서 해당 지점까지의 모든 줄을 건너뛰는 것입니다. 예를 들어

# Pipe the output of the if/then/else/fi construct to xargs.
# use the if/then/else/fi to select the input.
# Use '-s' to see if the file exists and has non zero size.
 if [ -s out.txt ] ; then
    # we have some existing data
    # Get the host from the last line
    # delete anything that is not the last line
    # remove the DIE/OK. quote anything not alphabetic with a backslash.
   lasthost="$(sed '$!d;s/^\(DIE\|OK\) //;s/[^0-9a-zA-Z]/\\&/g' out.txt)"
   # get the lines from 1m.txt from after the matched host
   # uses GNU sed extension to start at line "0"
   sed "0,/^$lasthost\$/d" 1m.txt
 else
   # no existing data, so just copy the 1m.txt using cat
   cat 1m.txt
 fi | xargs -I {} sh -c "if host {} >/dev/null; then echo OK {}; else echo DIE {}; fi" >> out.txt

그러나 작업을 병렬로 처리하고 있습니다. host반환 값은 서로 다른 시간이 걸릴 수 있으므로 입력을 크게 재배열할 수 있습니다 . 호스트가 확인되었는지 확인하는 더 빠른 방법이 필요합니다. 표준 접근 방식은 일종의 해시 테이블을 사용하는 것입니다. 한 가지 방법은 을 사용하는 것입니다 awk.

 if [ -s out.txt ] ; then
    # we have some existing data. Process the two files given
    # for the first file set the entries of the seen array to 1
    # for the second file print out the hosts which have not been seen. 
    awk 'FNR==NR {seen[$2]=1;next} seen[$1]!=1' out.txt 1m.txt
 else
   cat 1m.txt
 fi | xargs -I {} -P 100 sh -c "if host {} >/dev/null; then echo OK {}; else echo DIE {}; fi" >> out.txt

관련 정보