5 백만 개의 파일을 효율적으로 병합
부실한 계획으로 인해 약 20GB에 달하는 5 백만 개 이상의 파일이 포함 된 디렉토리가 있습니다. 각 파일은 상단에 32 줄의 쓰레기와 알 수없는 수의 중요한 데이터를 포함합니다.
중요한 데이터를 모두 하나의 파일로 병합하고 싶습니다.
나는 이것을하고 있었다 :
for i in $(find); do tail -n +32 $i >> ../all.txt; done
all.txt는 초당 약 .5MB 만 증가했습니다. 이를 수행하는 더 빠른 방법이 있습니까? 또한 작업을 완료하기 전에 디스크 공간이 부족할 가능성이 있으므로 이동하면서 파일을 제거하면 편리합니다 .X
조언을 부탁드립니다.
답변
이동하면서 파일을 삭제해야하는 경우 작성한 내용과 함께 이미 빠른 방법입니다. 한 가지 최적화는를 사용 find하여 파일 내용을 나열하는 대신 *에서 추가 처리 시간을 발생시키지 않고 디렉토리 목록에 나열된대로 파일을 나열하는를 사용할 수 있다는 것 입니다 find. 즉, 다음과 같이 작성합니다.
for i in *; do tail -n +3 $i >> ../x; rm $i; done
그러나 병합이 완료 될 때까지 삭제를 아끼지 않고 어떤 파일에서 어떤 콘텐츠를 가져 왔는지 유지하려면 한 번에 여러 개를 파싱하는 방법이 있습니다 (셸 수만큼). 허용). 이에 대한 명령은 다음과 같습니다.
find . -exec tail -n +3 {} >> ../x +
+말은 말할 것 find한 번에 파일 이름을 많이 전달하는 대신 한 번에 하나씩 할 수 있습니다. 이로 인해 ( tail호출 된 인스턴스 수가 훨씬 적기 때문에) 엄청난 성능 향상이 발생 하지만 출력 파일에는 여전히
==> ./filename <==
한 파일이 종료되고 다음 파일이 시작될 때마다 인쇄됩니다. 또한 파일은 이동 중에 삭제되지 않습니다.
약간의 속도를 내고 위의 줄을 제거하려면 다음을 통해 실행할 수 있습니다.
find . -exec awk 'FNR>32' {} +
(댓글로 제안 해 주신 dave_thompson에게 감사드립니다).
마지막으로, 당신은 어떤 정보 목록이있는 파일에서 왔다고 출력을 선호하고, 아직도 당신이 가서 그들을 삭제하려면, 당신은 모두,이 일을 iruvar의 답변을 사용한다면 \;'으로 대체 s의 +의 (내 원래의 대답'만 해야 할 일을 설명했습니다. iruvar가 실제 명령을 내 렸습니다).
귀하의 프로세스는 IO 바인딩 가능성이 있으므로 루프를 최적화하면 기껏해야 약간의 개선을 얻을 수 있습니다. 파일 깊이 우선 작업에 동의하면 tail및 rm호출을으로 롤링하여 find진행하면서 삭제할 수 있습니다.
GNU 사용 find:
find . -type f -exec tail -n +32 {} \; -delete >../all.txt
이상적으로는 로 대체 하여 find여러 파일을 tail한 번에 전달할 수 있기를 원 하지만 함께 작동하도록 할 수없는 것 같습니다.\;+-delete
A를 find그이 부족 -delete옵션을
find . -type f -exec tail -n +32 {} \; -exec rm {} \; >../all.txt
또는 여러 파일을 수신 할 때 파일 헤더의 인쇄를 억제 -q하기 tail위해 to 전달을 허용하는 GNU 시스템에서 tail:
find . -type f -exec tail -q -n +32 {} + -exec rm {} + >../all.txt
참고-를 사용 -exec rm하면 해당되는 깊이 우선 검색 -delete이 더 이상 적용되지 않습니다.이 마지막 주문은 가장 성능이 뛰어난 것으로 판명 될 가능성이 높습니다.