대용량 파일을 효율적으로 구문 분석

대용량 파일을 효율적으로 구문 분석

이라는 이름의 수십만 개의 파일이 있는 폴더 hp-temps.txt(및 수많은 하위 폴더)가 있습니다.

해당 파일의 내용은 다음과 같습니다.

Sensor   Location              Temp       Threshold
------   --------              ----       ---------
#1        PROCESSOR_ZONE       15C/59F    62C/143F 
#2        CPU#1                10C/50F    73C/163F 
#3        I/O_ZONE             25C/77F    68C/154F 
#4        CPU#2                32C/89F    73C/163F 
#5        POWER_SUPPLY_BAY     9C/48F     55C/131F 

모든 파일을 구문 분석하고 라인 #1에서 가장 높은 온도 항목을 찾아야 합니다.

작업 중인 스크립트가 있지만 시간이 오래 걸리고 이를 개선할 수 있는 방법이 있는지 알고 싶습니다.

저는 쉘 스크립팅을 처음 접했기 때문에 이 코드는 정말 비효율적이라고 생각합니다.

#!/bin/bash
highesetTemp=0
temps=$(find $1 -name hp-temps.txt -exec cat {} + | grep 'PROCESSOR' | cut -c 32-33)
for t in $temps
do
  if [ $t -gt $highestTemp ]; then
    highestTemp=$t
  fi
done

편집하다:

매우 효율적인 코드가 있지만 가장 큰 값만 필요한 것은 아니라는 점을 언급하는 것을 잊어버렸습니다.

더 높은 값이 감지되면 파일의 디렉터리와 온도를 출력하고 싶기 때문에 모든 파일을 반복할 수 있기를 원합니다.

따라서 출력은 다음과 같습니다.

New MAX: 22 in /path/to/file/hp-temps.txt
New MAX: 24 in /another/path/hp-temps.txt
New MAX: 29 in /some/more/path/hp-temps.txt

답변1

중간 데이터를 문자열로 저장하는 것은 느리고 거의 필요하지 않습니다. 일반적인 경우 단일 스칼라 변수에 여러 문자열을 저장하는 데는 추가적인 문제가 있습니다. 이와 같이 각 하위 문자열에는 공백이나 기타 문자가 포함될 수 있으며 나중에 따옴표 없이 루프 방식을 사용하여 쉘을 강제로 사용하여 해결할 수 있습니다. 문자열을 분할합니다 for(배열을 사용하는 것이 더 좋습니다).

이 경우 각 파일을 찾아 온도를 추출하고 해당 온도 스트림을 읽는 것이 더 효율적입니다. 또한 300KB(또는 그 이상)의 문자열을 포함하는 셸 변수 생성을 방지합니다.

섭씨 온도는 다음에서 분석할 수 있습니다.하나파일 사용량

awk '$2 == "PROCESSOR_ZONE" { printf "%d\n", $3 }' file

두 번째 필드가 문자열인 경우 세 번째 필드의 온도를 출력합니다 PROCESSOR_ZONE. 쓰기 시 세 번째 필드를 정수로 변환하므로 값의 첫 번째 부분만 출력됩니다(숫자가 아닌 첫 번째 부분까지).

다음에서 호출됨 find:

find . -name hp-temps.txt \
    -exec awk '$2 == "PROCESSOR_ZONE" { printf "%d\n", $3 }' {} +

이는 awk발견된 파일의 하나 이상의 배치에 대해 명령을 실행하고 표준 출력에 온도를 차례로 인쇄합니다.

awk비표준 명령문을 이해하는 것을 사용하는 경우 nextfile이를 사용하여 가능한 한 빨리 다음 파일로 이동할 수 있습니다.

find . -name hp-temps.txt \
    -exec awk '$2 == "PROCESSOR_ZONE" { printf "%d\n", $3; nextfile }' {} +

위 명령으로 출력된 최대값을 찾으려면 다음 awk명령을 사용할 수도 있습니다.

awk 'NR == 1 || $1 > max { max = $1 } END { print max }'

awkmax변수 값이 지금까지 확인된 첫 번째 값이거나 가장 큰 값인 경우 현재 입력 값으로 설정합니다. 마지막 max출력 값입니다.

나는 이것이 쉘 루프보다 몇 배 더 빠를 것으로 기대합니다.

종합해보면:

find . -name hp-temps.txt \
    -exec awk '$2 == "PROCESSOR_ZONE" { printf "%d\n", $3; nextfile }' {} + |
awk 'NR == 1 || $1 > max { max = $1 } END { print max }'

가장 큰 값을 갖는 파일의 파일명을 찾아 달라는 추가 요청이 있습니다. 각 파일의 값과 함께 파일 이름을 전달하면 됩니다. 에서는 awk현재 입력 파일의 경로 이름을 특수 변수로 사용할 수 있습니다 FILENAME.

find . -name hp-temps.txt \
    -exec awk '$2 == "PROCESSOR_ZONE" { printf "%d\t%s\n", $3, FILENAME; nextfile }' {} + |
awk 'NR == 1 || $1 > max { max = $1; fname = $2 } END { print max, fname }'

여러 파일의 최대값이 동일한 경우 발견된 첫 번째 파일의 파일 이름이 보고됩니다 find. 유틸리티는 find나열된 순서대로 파일을 찾습니다.ls -f

관련 정보