sed를 사용하여 대용량 파일을 효율적으로 제자리에서 제거합니까?


24

아래 명령은 파일 크기에 따라 몇 분이 걸릴 수 있습니다. 더 효과적인 방법이 있습니까?

sed -i 1d large_file 

답변:


34

ed대신 시도하십시오 :

ed <<< $'1d\nwq' large_file

"대형"이 약 1 천만 라인 이상을 의미하는 경우 더 잘 사용하십시오 tail. 전체 편집은 할 수 없지만 성능으로 인해 용서할 수 없습니다.

tail -n +2 large_file > large_file.new

시간 차이를 표시하도록 편집하십시오 .

( awkJaypal의 코드는 동일한 머신 (CPU 2.2GHz)에서 실행 시간을 갖도록 추가되었습니다.)

bash-4.2$ seq 1000000 > bigfile.txt # further file creations skipped

bash-4.2$ time sed -i 1d bigfile.txt
time 0m4.318s

bash-4.2$ time ed -s <<< $'1d\nwq' bigfile.txt
time 0m0.533s

bash-4.2$ time perl -pi -e 'undef$_ if$.==1' bigfile.txt
time 0m0.626s

bash-4.2$ time { tail -n +2 bigfile.txt > bigfile.new && mv -f bigfile.new bigfile.txt; }
time 0m0.034s

bash-4.2$ time { awk 'NR>1 {print}' bigfile.txt > newfile.txt && mv -f newfile.txt bigfile.txt; }
time 0m0.328s

의 경우 tail, 차라리 할 시간 계산 것 모두 첫 번째 줄을 제거 하고 교체 bigfile.txt로를 bigfile.new.
rozcietrzewiacz

@rozcietrzewiacz, 요점은 맞습니다. 고맙습니다. 업데이트되었습니다.
manatwork

정말 멋지다! 내가 가진 동일한 한 awk다음과 같은 결과를 얻었다 -[jaypal:~/Temp] seq 1000000 > bigfile.txt [jaypal:~/Temp] time awk 'NR>1 {print}' bigfile.txt >newfile.txt real 0m0.649s user 0m0.601s sys 0m0.033s
jaypal을 싱

1
@Jaypal, 대안 목록에 코드를 추가했습니다. 내 컴퓨터에서는 훨씬 빨랐습니다. 이상하게, 나는 awk성능이 ~에 더 가까울 것으로 예상했다 sed. (나 자신에게주의 : 기대하지 마십시오-대신 테스트하십시오.)
manatwork

이것은 내 경우에 가장 좋은 해결책이었습니다 tail -n +2 bigfile.txt > bigfile.new && mv -f bigfile.new bigfile.txt;. 여러 프로세스가 사용하는 단일 작업 목록을 추적하기 위해 잠금이있는 단일 파일을 사용하고 있습니다. 초기 포스터가 사용한 것부터 시작했습니다 sed -i 1d large_file . 이로 인해 파일이 1-2 초 동안 잠겼습니다. tail/mv콤보는 거의 즉시 완료됩니다. 고맙습니다!
Chris Adams

6

파일 시작 부분에서 효율적으로 항목을 제거 할 수있는 방법이 없습니다. 처음부터 데이터를 제거하려면 전체 파일을 다시 작성해야합니다.

파일 끝에서 잘리는 것은 매우 빠를 수 있습니다 (OS는 파일 크기 정보 만 조정하면 현재 사용하지 않는 블록을 지울 수 있음). 일반적으로 파일 헤드에서 제거하려고 할 때는 불가능합니다.

전체 블록 / 익스텐트를 정확하게 제거하면 이론적으로 "빠른"것일 수 있지만 시스템 호출이 없으므로 파일 시스템 별 의미 체계 (존재하는 경우)에 의존해야합니다. (또는 첫 번째 블록 안에 파일 형식이 있거나 파일의 실제 시작을 표시하는 범위가 있다고 생각합니다.


파일이 매우 큰 경우 줄 끝을 처리하는 데 필요한 CPU 오버 헤드보다 I / O 오버 헤드가 더 클 수 있습니다.
Mat

네 말이 맞아 그러나 도구가 파일 내용에 액세스하는 방식에 차이가있을 수 있습니다. 가장 좋은 것은 필요하지 않은 경우 한 줄씩 처리하지 않거나 필요하지 않은 경우 한 줄씩 읽지 않는 것입니다.
manatwork

2
결과의 차이가 너무 커서 여기에서 해당 파일 크기로 재현 할 수 있습니다. 파일 크기가 증가함에 따라 이점이 줄어드는 것처럼 보입니다 (시퀀스 10M, sed의 경우 15 초, ed의 경우 5 초로 시도). 어쨌든 좋은 팁 (+1).
Mat

버전 3.15부터 Linux에는 이제 어느 정도 기반 파일 시스템에서 파일의 일부 를 축소 하는 API가 있지만 적어도 전체 블록 (일반적으로 4k)에서만 수행 할 수있는 ext4의 경우가 있습니다.
Stéphane Chazelas

편집시 전체 파일을 다시 작성해야하더라도 효율적으로 편집 할 수있는 명령 줄 도구를 사용하는 것이 매우 편리합니다. 필자의 경우 전체 시스템 RAM보다 큰 파일의 첫 줄을 제거해야 할 때 도움이되었습니다.
Jason

3

가장 효율적인 방법은하지 마십시오! 어떤 경우 든 디스크에 '큰'공간의 두 배가 필요하고 IO가 낭비됩니다.

첫 번째 줄없이 읽을 큰 파일이 있으면 첫 번째 줄을 제거하기 위해 읽을 때까지 기다리십시오. stdin에서 프로그램으로 파일을 보내야하는 경우 tail을 사용하여 수행하십시오.

tail -n +2 | your_program

파일을 읽어야 할 경우 디스크에 필요한 공간이있는 경우에만 첫 번째 줄을 제거 할 수 있습니다.

tail -n +2 | tee large_file2 | your_program

stdin에서 읽을 수 없으면 fifo를 사용하십시오.

mkfifo large_file_wo_1st_line
tail -n +2 large_file > large_file_wo_1st_line&
your_program -i large_file_wo_1st_line

bash를 사용하는 경우 프로세스 대체를 활용하십시오.

your_program -i <(tail -n +2 large_file)

파일을 찾아야하는 경우 처음부터 파일에 갇히지 않는 것보다 더 나은 해결책을 찾지 못합니다. 이 파일이 stdout에 의해 생성 된 경우 :

large_file_generator | tail -n +2 > large_file

그렇지 않으면 항상 fifo 또는 프로세스 대체 솔루션이 있습니다.

mkfifo large_file_with_1st_file
large_file_generator -o large_file_with_1st_file&
tail -n +2 large_file_with_1st_file > large_file_wo_1st_file

large_file_generator -o >(tail -n 2+ > large_file_wo_1st_file)

1

Ex 모드에서 Vim을 사용할 수 있습니다 :

ex -sc '1d|x' large_file
  1. 1 첫 줄을 선택하십시오

  2. d 지우다

  3. x 저장하고 닫습니다


0

이것은 단지 이론적 인 것이지만 ...

사용자 정의 파일 시스템 (FUSE 또는 이와 유사한 메커니즘을 사용하여 구현 됨)은 기존 디렉토리와 내용이 동일하지만 원하는대로 파일이 잘린 디렉토리를 노출시킬 수 있습니다. 파일 시스템은 모든 파일 오프셋을 변환합니다. 그러면 시간이 많이 걸리는 파일 재 작성이 필요하지 않습니다.

그러나 이러한 아이디어가 수십 테라 바이트의 파일을 가지고 있지 않다면 이러한 파일 시스템을 구현하는 것은 너무 비싸고 시간이 많이 걸리는 실용적이지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.