10000 단어(한 줄에 한 단어)가 포함된 Words.txt가 있습니다. 5,000개의 문서가 있습니다. 어떤 문서에 어떤 단어가 포함되어 있는지 확인하고 싶습니다(단어 주위의 정규식 패턴 사용). 문서를 grep하고 조회수를 출력하는 script.sh가 있습니다. 나는 (1) 입력 파일을 더 작은 파일로 분할하고 (2) 각 파일을 script.sh에 대한 인수로 제공하고 (3) 모든 파일을 병렬로 실행하고 싶습니다.
내 시도는 다음을 기반으로합니다.지도 시간오류가 발생했습니다.
$parallel ./script.sh ::: split words.txt # ./script.sh: line 22: split: No such file or directory
내 script.sh는 다음과 같습니다
#!/usr/bin/env bash
line 1 while read line
line 2 do
some stuff
line 22 done < $1
grep 명령이 시작된 디렉터리의 파일을 통해 출력을 디렉터리 루프로 분할할 수 있다고 가정합니다. 하지만 이를 우아하고 간결하게(병렬 처리를 사용하여) 수행하는 방법은 무엇입니까?
답변1
STDIN에서 읽는 중이므로 임시 파일이 필요하지 않을 수도 있습니다. 따라서 실제로 사용할 이유가 없습니다 split
. 다음 명령을 사용하여 파일을 삭제합니다 --pipe
.
cat words | parallel --pipe -L 1000 -N1 ./script.sh
원하는 것을 grep하는 경우 :
find dir-with-5000-files -type f | parallel -X grep -f words.txt
너무 커서 메모리에 맞지 않으면 words.txt
분할할 수 있습니다.
find dir-with-5000-files -type f | parallel -X "cat words.txt | parallel --pipe grep -f -"
GNU Parallel의 매뉴얼 페이지에는 m개의 정규 표현식 n줄을 가장 효율적으로 잡는 방법이 설명되어 있습니다.https://www.gnu.org/software/parallel/parallel_examples.html#example-grepping-n-lines-for-m-regular-expressions
정규식이 많은 대용량 파일을 grep하는 가장 간단한 솔루션은 다음과 같습니다.
grep -f regexps.txt bigfile
또는 정규식이 고정 문자열인 경우:
grep -F -f regexps.txt bigfile
CPU와 디스크 I/O라는 두 가지 제한 요소가 있습니다. CPU는 측정하기 쉽습니다. grep이 CPU의 90%를 초과하는 경우(예: top 실행 시) CPU가 제한 요소이므로 병렬화가 속도를 높입니다. 그렇지 않은 경우 디스크 I/O가 제한 요소이며 디스크 시스템에 따라 병렬화가 더 빨라질 수도 있고 느려질 수도 있습니다. 확실히 알 수 있는 유일한 방법은 측정하는 것입니다.
CPU가 제한 요소인 경우 정규식을 병렬화해야 합니다.
cat regexp.txt | parallel --pipe -L1000 --round-robin grep -f - bigfile
이는 CPU당 하나의 grep을 시작하고 CPU당 한 번 큰 파일을 읽습니다. 그러나 이 작업은 병렬로 수행되므로 첫 번째 읽기를 제외한 모든 읽기가 RAM에 캐시됩니다. regexp.txt의 크기에 따라 -L1000 대신 --block 10m을 사용하는 것이 더 빠를 수도 있습니다. regexp.txt가 너무 커서 RAM에 맞지 않으면 --round-robin을 제거하고 -L1000을 조정하십시오. 이렇게 하면 빅파일을 더 많이 읽을 수 있습니다.
일부 스토리지 시스템은 여러 블록을 병렬로 읽을 때 성능이 더 좋습니다. 이는 일부 RAID 시스템 및 일부 네트워크 파일 시스템에 해당됩니다. 대용량 파일을 병렬로 읽기:
parallel --pipepart --block 100M -a bigfile grep -f regexp.txt
그러면 빅파일이 100MB 청크로 분할되고 각 청크에 대해 grep이 실행됩니다. bigfile과 regexp.txt를 병렬로 읽으려면 --fifo를 사용하여 두 가지를 결합하십시오.
parallel --pipepart --block 100M -a bigfile --fifo cat regexp.txt \
\| parallel --pipe -L1000 --round-robin grep -f - {}
답변2
이 split
도구를 사용하여 다음을 수행할 수 있습니다.
split -l 1000 words.txt words-
파일을 여러 파일로 분할합니다 words.txt
. 각 파일의 이름은 1000줄 이하로 지정해야 합니다.
words-aa
words-ab
words-ac
...
words-ba
words-bb
...
접두사가 생략된 경우( words-
위 예에서) 기본 접두사 split
로 사용됩니다 .x
생성된 파일을 사용하려면 parallel
glob을 사용할 수 있습니다.
split -l 1000 words.txt words-
parallel ./script.sh ::: words-[a-z][a-z]