오늘의 Perl - 리스트 비교

in dev •  7 years ago 

입개발 챗방에서 떠들다가

"파일이 수백만개 있고, 파일리스트가 하나 있는데 이 파일리스트에 없는 파일을 지워야 한다" 라는 애환(?)을 듣고 재빨리 방법을 생각해 봤습니다.

우선 find 로 존재하는 파일리스트를 만들고 최종적으로 삭제할 파일리스트를 만들면 파일이고 뭐고 그냥 두개의 리스트를 비교하는 문제가 됩니다.

정리하자면

  • list1.txt : 전체 파일 리스트
  • list2.txt : 지우지 말아야할 파일 리스트

따라서 list1.txt 에는 있고 list2.txt 에는 없는 파일들을들 list3.txt 에 쓰면 됩니다.

  • list3.txt 삭제할 파일 리스트

예전엔 이런 걸 밥먹듯이 했었는데

  • 리스트가 100줄 근처 라면 그냥 grep 으로 해결합니다.
grep -vf list2.txt list1.txt > list3.txt
  • 리스트가 10000줄 이하라면 정렬을 한 후 comm 이나 diff 를 이용합니다.
sort list1.txt > s_list1.txt
sort list2.txt > s_list2.txt
comm -23 s_list1.txt s_list2.txt

리스트가 수 만줄을 넘어가면 이 방법도 문제가 생기는데 , 그럴때 해시테이블을 사용합니다. 전 주로 perl 을 사용하죠

 perl -ne'BEGIN{$h{$_}++for`cat list2.txt`}print unless $h{$_}' list1.txt > list3.txt

1000 만줄 정도 테스트했더니 10초 걸립니다.

그런데 문제가 하나 있습니다.
헤시 테이블은 메모리를 사용하는데 1000만줄 list1.txt 에 700만줄 list2.txt 를 사용했더니 메모리를 무려 1.5GiB 나 먹습니다.
전 각 줄에 숫자를 사용했는데 파일 경로처럼 더 긴 문자열이면 심각한 문제가 생길 수 있습니다.

몇가지 해결책을 찾을 수 있을 것 같은데 제가 생각한 가장 간단한 방법은 이렇습니다.
list1.txt 에 있고 list2.txt 에 없는 파일을 찾는 것이니까, list2.txt 를 여러 파일로 나눈 후 여러번 필터링을 해도 같은 효과가 납니다. 디스크 IO 가 늘어나고 좀 더 느려지겠지만요.
코드는 간단합니다.

# 먼저 list2.txt 를 백만줄 단위로 나눕니다.
split -l 1000000 list2.txt
# list 1 의 임시파일을 만듭니다.
cp list1.txt tmp.txt
# 나누어진 list2.txt 에 대해 각각 시행합니다.
ls x* | while read x;do
  perl -ne'BEGIN{$h{$_}++for`cat '$x'`}print unless $h{$_}' tmp.txt > ${x}.txt
  mv ${x}.txt tmp.txt
done
mv tmp.txt list3.txt
rm x*

타다~

이제 메모리는 250MiB 정도이고 시간은 25초 가량 걸리네요.

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

Congratulations @paul9! You received a personal award!

1 Year on Steemit

Click here to view your Board

Support SteemitBoard's project! Vote for its witness and get one more award!

Congratulations @paul9! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 2 years!

You can view your badges on your Steem Board and compare to others on the Steem Ranking

Vote for @Steemitboard as a witness to get one more award and increased upvotes!