총 디스크 공간이 1TB이고 여유 공간이 300GB인 시스템의 700GB 텍스트 파일에서 처음 3억 줄을 어떻게 삭제합니까? (내 시스템에는 2GB의 RAM이 있습니다.) 내가 찾은 답변은 sed, tail, head를 사용합니다.
하지만 제 생각에는 (수정해주세요) 디스크 공간이 1TB로 제한되어 있고 처리 중에 새 파일을 생성하거나 tmp 파일이 있기 때문에 사용할 수 없습니다.
이 파일에는 JSON 형식의 데이터베이스 레코드가 포함되어 있습니다.
답변1
처음 n 줄(또는 바이트)을 삭제하려면 다음 dd
을 사용할 수 있습니다.순환 장비를 사용하세요). 임시 파일을 사용하지 않으며 크기 제한도 없습니다. 그러나 진행 상황 추적이 없고 오류가 발생하면 파일이 손상될 수 있으므로 위험합니다.
예:1000줄 예제 파일을 만듭니다.
$ seq 1 1000 > 1000lines.txt
$ head -n 3 1000lines.txt
1
2
3
$ tail -n 3 1000lines.txt
998
999
1000
처음 300개 행을 삭제하려고 합니다. 몇 바이트에 해당합니까?
$ stat -c %s 1000lines.txt
3893 # total bytes
$ head -n 300 1000lines.txt | wc -c
1092 # first 300 lines bytes
$ echo $((3893-1092))
2801 # target filesize after removal
파일은 3893바이트이고 처음 1092바이트를 삭제하고 2801바이트의 새 파일을 남겨두려고 합니다.
이러한 바이트를 제거하려면 GNU dd
명령을 사용합니다. conv=notrunc
그렇지 않으면 파일 내용이 복사되기 전에 파일이 삭제됩니다.
$ dd conv=notrunc iflag=skip_bytes skip=1092 if=1000lines.txt of=1000lines.txt
5+1 records in
5+1 records out
2801 bytes (2.8 kB, 2.7 KiB) copied, 8.6078e-05 s, 32.5 MB/s
이렇게 하면 처음 300줄이 삭제되지만 파일이 아직 잘리지 않았기 때문에 이제 마지막 1092바이트가 복제됩니다.
$ truncate -s 2801 1000lines.txt
이렇게 하면 파일이 최종 크기로 축소되고 파일 끝에 중복된 줄이 제거됩니다.
결과:
$ stat -c %s 1000lines.txt
2801
$ head -n 3 1000lines.txt
301
302
303
$ tail -n 3 1000lines.txt
998
999
1000
더 큰 파일의 경우에도 프로세스는 비슷합니다. 더 나은 성능을 위해 더 큰 블록 크기를 설정해야 할 수도 있습니다(블록 크기 옵션 dd
은 bs
).
주요 문제는 정확한 줄 번호에 대한 올바른 바이트 오프셋을 결정하는 것입니다. 일반적으로 이는 읽고 세기를 통해서만 수행할 수 있습니다. 이 접근 방식을 사용하면 파일의 많은 부분을 삭제하더라도 전체 파일을 한 번 이상 읽어야 합니다.
답변2
파일을 압축할 공간이 충분하면 많은 공간이 확보되어 다른 작업을 수행할 수 있습니다. 다음을 시도해 볼 수 있습니다.
gzip file && zcat file.gz | tail -n +300000001 | gzip > newFile.gz
그러면 먼저 gzip
원본 입력 파일( file
) 이 생성됩니다 file.gz
. 그런 다음 zcat
새로 생성된 file.gz
파이프를 tail -n +300000001
통해 처음 3M 행을 제거하고 결과를 압축하여 디스크 공간을 절약 한 다음 newFile.gz
. .&&
gzip
텍스트 파일은 압축 가능성이 매우 높습니다. 예를 들어, 1부터 400,000,000까지의 숫자를 인쇄하는 테스트 파일을 만들었고 seq 400000000 > file
그 결과 파일 크기는 3.7G가 되었습니다. 위 명령어를 이용하여 압축을 해보니 압축파일은 849M 밖에 안되고 newFile.gz
제가 만든 파일은 213M 밖에 안되네요.
답변3
일부 파일 시스템(예: ext4 또는 xfs)에서는 fallocate()
시스템 호출을 사용할 수 있습니다.
답변4
작업이 정말로 필요한 경우 커스터마이저에 다시 투표하세요. C 또는 Perl이나 Python과 같은 충분히 강력한 동적 언어라면 가능합니다. 여기서는 소스 코드를 작성하지 않고 데이터 이동 시 데이터 손실을 방지하는 알고리즘에 대해 설명하겠습니다.
- 줄 바꿈을 세면서 끝부터 큰 파일을 읽습니다. 사용 가능한 공간에 안전하게 들어갈 수 있는 미리 정의된 행 수를 수집한 후 이 블록을 별도의 파일에 쓰고 큰 파일의 끝 부분을 잘라냅니다. 라인 번호를 저장하려면 블록의 파일 이름을 사용하십시오.
- 그 후에는 완전히 지워진 대용량 파일과 동일한 공간을 차지하는 많은 작은 파일을 얻게 됩니다.
- 3억 개의 행을 계산하세요. 어떤 블록에 어떤 행이 포함되어 있는지 알 수 있으므로 불필요한 행에 해당하는 모든 블록을 즉시 삭제할 수 있습니다.
- 실제로 큰 파일이 필요하지 않은 경우 와일드카드를 사용하거나 필요에 따라 문자열을 연결하여 원하는 도구를 사용하여 나머지 청크에서 직접 작업할 수 있습니다
cat
. - 결국 대용량 파일이 필요하고 불필요한 파일을 삭제한 후 확보된 공간이 나머지 블록의 합계를 저장하기에 충분하다면
cp
또는 로 결합하기만 하면 됩니다cat
. - 큰 파일이 필요하고 공간이 충분하지 않은 경우 1단계와 반대되는 작업을 수행하는 또 다른 작은 프로그램을 작성하십시오. 목록과 각 청크의 개별 길이를 일부 목록 파일에 저장하십시오. 청크를 하나씩 읽고 새로 생성된 "큰 파일"에 추가합니다. 큰 파일에 청크를 추가할 때마다 해당 청크가 포함된 별도의 작은 파일을 삭제하여 파일을 제자리에 다시 조립할 수 있습니다. 언제든지 블록 쓰기 프로세스를 중단한 경우 각 블록의 크기를 미리 저장했기 때문에 특정 블록에 대한 올바른 오프셋을 계산하여 대용량 파일 쓰기를 다시 시작할 수 있습니다.