VAR=`cat file`을 사용한 후 echo "$VAR"을 반복하는 것은 cat 파일을 반복하는 것보다 느립니다. 왜?

VAR=`cat file`을 사용한 후 echo "$VAR"을 반복하는 것은 cat 파일을 반복하는 것보다 느립니다. 왜?

files/.NET 파일에는 약 10,000개의 파일 과 10,000개의 줄이 있습니다 metadata.csv. metadata.csv파일에 대한 정보가 포함되어 있습니다 . 각 파일에 대한 정보를 인쇄한 다음 파일의 내용을 인쇄하는 쉘 스크립트가 있습니다.

#!/bin/sh
for FILE in `find files/ -type f`
do
    ID=`echo $FILE | sed 's/some/thing/'`
    cat metadata.csv | awk -v ORS="" -v id=$ID -F "\t" '$1==id {
        print "id=\""id"\" Some=\""$2"\" Thing=\""$5"\" "}'
    cat $FILE
done

metadata.csv내용을 변수에 할당하면 작업 속도가 빨라질 수 있다고 생각합니다 METADATA. 나는 매번 디스크에서 파일을 읽지 않고 메모리에 저장한다고 생각합니다.

#!/bin/sh
METADATA=`cat metadata.csv`
for FILE in `find files/ -type f`
do
    ID=`echo $FILE | sed 's/some/thing/'`
    echo "$METADATA" | awk -v ORS="" -v id=$ID -F "\t" '$1==id {
        print "id=\""id"\" Some=\""$2"\" Thing=\""$5"\" "}'
    cat $FILE
done

그러나 두 번째는 빠르지 않았습니다. 첫 번째는 약 1분 동안 실행되고 두 번째는 2분 이상 실행됩니다.

어떻게 작동하며 두 번째 스크립트가 더 빠른 대신 느린 이유는 무엇입니까?

편집하다:/bin/sh -> 내 시스템에서 대시

답변1

다른 사람이 벤치마크를 재현할 수 있을 만큼 충분한 정보를 제공하지 않습니다. 제가 직접 만들어 봤는데 echodash와 ksh를 사용하는 방법이 조금 더 빠르며, mksh를 사용하는 방법도 거의 같습니다. 차이가 있더라도 비율은 1:2보다 훨씬 적습니다. 분명히 이것은 쉘, 커널, 유틸리티 구현, 데이터 파일의 내용을 포함한 많은 것들에 따라 달라집니다.

이 두 가지 방법 사이에는 확실한 승자가 없습니다. 파일이 캐시에 있기 때문에 디스크에서 읽는 것은 실제로 비용이 들지 않습니다. 호출에는 cat외부 프로세스를 포크하는 오버헤드가 있으며 echo쉘은 bultin입니다. shbash를 사용하는 경우 echo내장 함수는 출력이 파이프로 들어가더라도 인수를 한 번에 한 줄씩 인쇄하는데, 이는 속도 저하의 원인 중 하나일 수 있습니다. Dash와 ksh는 이 작업을 수행하지 않습니다. 일반적으로 bash보다 성능이 더 좋습니다.

스크립트에서 수행할 수 있는 최적화가 많이 있습니다.

  • 이 방법의 확실한 최적화는 cat리디렉션()을 사용 <metadata.csv awk …하거나 metadata.csv이를 awk에 매개변수로 전달하는 것입니다. 내 테스트에서는 리디렉션이 리디렉션보다 약간 빨랐으며 echo리디렉션과 리디렉션 간에는 측정 가능한 차이가 없었습니다 awk … metadata.csv.

  • 따옴표 없이 변수 확장을 사용하는 경우값에 특정 문자가 포함되어 있으면 심각하게 실패합니다., 이는 분할 및 글로빙을 수행해야 하기 때문에 셸에 대한 추가 작업을 생성합니다. 변수 대체를 생략해야 하는 이유를 모르는 경우에는 항상 큰따옴표를 사용하십시오.

  • find마찬가지로 특정 파일 이름을 차단하고 추가 작업이 필요한 출력을 구문 분석하고 있습니다 . 표준 솔루션은 find -exec; 를 사용하는 것이지만 파일을 처리하기 위해 셸을 시작하려면 추가 작업이 필요하기 때문에 더 빠를 수도 있고 그렇지 않을 수도 있습니다.
  • 귀하의 awk 스크립트는 실제 스크립트에서 단순화되었다고 생각합니다. 표시되는 스크립트를 사용하여 CSV 파일의 첫 번째 열에 정규식에서 특별하지 않은 문자만 포함되어 있다고 가정하면 대신 sed를 사용해 볼 수 있지만 일반적으로 보다 전문화된 도구가 있기 때문에 조금 더 빠를 수 있습니다. 더 빨리. 하지만 측정 가능한 수준은커녕 개선된다는 보장도 없습니다.
  • 설정을 하면 ID외부 프로그램을 호출하게 됩니다. 여기서 정확히 무엇을 하느냐에 따라 쉘 자체의 문자열 조작 구성을 사용하여 이것이 가능할 수도 있습니다. 일반적으로 그다지 빠르지도 강력하지도 않지만 외부 프로그램을 호출할 필요가 없습니다.

전체적으로 이러한 로컬 최적화와 결합하여 저는 다음을 선택하겠습니다.

#!/bin/ksh
find files/ -type f -exec sh -c '
  for FILE do
    ID=${FILE//some/thing}
    sed '/^$ID\t/ s/\([^\t]*\)\t\([^\t]*\)\t[^\t]*\t[^\t]*\t\([^\t]*\).*/id="\1" Some="\2" Thing="\3"/' metadata.csv
    cat "$FILE"
  done' _ {} +

그러나 더 빠른 알고리즘이 있을 수 있습니다. 각 파일에 대한 전체 메타데이터 세트를 처리하고 있습니다. 특히 파일당 한 줄만 일치시키는 경우 불필요한 비교가 많이 생성됩니다. 파일 이름에서 ID 목록을 생성하고 이를 메타데이터와 비교하는 것이 더 빠를 수 있습니다. 테스트되지 않은 코드:

#!/bin/ksh
join -j 1 -t $'\t' -o 2.1,2.2,2.5,1.2 \
     <(find files/ -type f | sed 's!/some$!/thing\t&!' | sort) \
     <(sort metadata.csv) |
awk -F '\t' '{
    print "id =\"" $1 "\" Some=\"" $2 "\" Thing=\" $3 "\"";
    system("cat \047" $4 "\047"); # Assuming no single quotes in file names
}'

관련 정보