파일의 시작 부분(제자리, 동일한 inode)에서 자를 수 있습니까?

파일의 시작 부분(제자리, 동일한 inode)에서 자를 수 있습니까?

file새 파일에 쓰고( > newfile) 다시 이동하지 않고도( ) 의 후행 바이트를 제거할 수 있습니다 mv newfile file. 이는 다음을 통해 수행됩니다 truncate.

truncate -s -1 file

선행 바이트를 제거할 수 있지만 이를 이동하면(inode가 변경됨) (일부 tail 버전의 경우):

tail -c +1 file > newfile ; mv newfile file

그렇다면 파일을 이동하지 않고 이를 수행하는 방법은 무엇입니까?
이상적으로는 잘라내기와 마찬가지로 매우 큰 파일의 경우에도 몇 바이트만 변경하면 됩니다.

참고: sed -i파일 inode를 변경하므로 유용하더라도 이 질문에 대한 답변은 아닙니다(IMO).

답변1

그리고 ksh93:

tail -c+2 < file 1<>; file

( 리디렉션된 명령이 성공하면 결국 파일을 자르는 표준 연산자의 ksh93 특정 변형 <>;입니다 .)<>

첫 번째 바이트는 제거됩니다(파일의 나머지 부분을 자체에 쓰고 끝 부분을 잘라냄).

다음을 사용하여 동일한 작업을 수행할 수 있습니다 sh.

{
  tail -c+2 < file &&
    perl -e 'truncate STDOUT, tell STDOUT'
} 1<> file

예정이니 참고해주세요드물지 않은희박한 파일(나중에 다시 구멍을 파낼 수는 있지만 fallocate -d)

읽기/쓰기 오류가 발생하면 tail종료되어 파일을 부분적으로 덮어쓴 채로 남을 수 있습니다(예를 들어 다시 쓰기 후에 실패 abcdefgh할 수 있음 ). 오류가 발생할 때 쓰기 오프셋을 보고하여 데이터를 복구하는 방법을 알 수 있도록 위의 내용을 조정할 수 있습니다. 아직 있습니다 :bcddefghbcdksh93

unset -v offset
{ tail -c+2 < file || false >#((offset=CUR)); } 1<>; file

$offset그런 다음 성공적으로 작성된 데이터의 양을 포함하는 if를 설정합니다 .

Linux(3.15 이후) 및 ext4 또는 xfs 파일 시스템에서는 다음을 수행할 수 있습니다.무너지다fallocate()시스템 호출이나 유틸리티의 파일 시스템 블록 크기의 배수인 크기 및 오프셋 또는 바이트의 범위입니다 fallocate.

예를 들어

fallocate -c -l 8192 file

파일의 나머지 부분을 다시 쓸 필요 없이 파일의 처음 8192바이트가 삭제됩니다(FS 블록 크기가 8192의 제수라고 가정). 그러나 FS 블록 크기의 배수가 아닌 부분을 삭제하려는 경우에는 소용이 없습니다.

답변2

"매우 큰 파일"의 의미에 따라 다릅니다. 당신의 한계는 무엇입니까?

전체 내용을 메모리(awk 문자열로)로 읽고 하위 문자열을 다시 원본 파일에 쓸 수 있습니다. 어떤 단계에서는 awk에 원시 데이터와 하위 문자열이 모두 포함되지만 0.5GB의 경우 이는 실행 가능한 솔루션입니다. awk는 내 노트북에서 초당 약 80MB를 처리할 수 있습니다.

C에서는 쓰기 시작 포인터를 이동하기만 하면 쉽습니다.

답변3

C에서는 동일한 inode를 사용하고 작업 파일을 사용하지 않으므로 매우 간단합니다. 다만 조심해서 잘 해야 합니다. 2의 거듭제곱이면 충분할 수 있지만(예: 64K) 장치의 블록 크기(예: 4096)를 찾기 위해 예비 쿼리를 수행해야 할 수도 있습니다.

데이터 흐름을 애벌레처럼 시각화합니다. 즉, 데이터가 새로운 위치로 이동할 수 있도록 앞으로 뻗어나가는 것입니다.

읽기/쓰기용으로 파일을 열고 시스템 호출 읽기/쓰기 내에서 모든 작업을 수행하여 FILE* 루틴에서 발생할 수 있는 버퍼링 문제를 방지합니다.

파일의 앞부분(N)에서 제거할 바이트 수는 전체 블록 수와 일부 예비 바이트 수입니다(이러한 구성 요소 중 하나 또는 둘 다 0일 수 있음).

A를 찾고 X * 4096바이트를 읽습니다. 여기서 X는 (효율성을 위해) 큰 것으로 선택되지만 어리석게 크지는 않습니다. 어쩌면 4MB 버퍼가 최적의 선택일 수도 있습니다.

0을 찾고, 이 버퍼에 필요한 전체 블록 수를 기록합니다. 내가 종이에서 본 바에 따르면, 결코 스스로 래핑되지 않습니다. 읽지 않은 다음 바이트는 이전 블록에 있을 수 없습니다.

파일이 부족해질 때까지 헹구고 반복하세요(검색 사이에 4MB 추가). 짧은 블록을 올바르게 처리하십시오.

이렇게 하면 마지막 N 바이트의 추가 복사본이 남게 되며, 시스템 호출로 이를 잘라낼 수 있습니다.

성능이 좋아야 합니다. 쓰기는 블록 정렬됩니다. 이론적으로 각 읽기에는 중복으로 인해 두 개의 블록 액세스가 필요하지만 순차 읽기에서는 이를 방지합니다(예: 4MB는 1024 블록 대신 1025 블록을 읽습니다).

dd 명령을 사용하면 스크립트에서 이 작업을 수행할 수 있다고 생각하지만 dd의 블록 크기 옵션은 검색과 읽기 모두에 적용되므로 매우 비효율적입니다.

테스트 방법: 100MB의 무작위 데이터 파일을 가져와서 cksum을 계산합니다. 그런 다음 더 작은 N바이트 파일에 추가합니다. 코드 cksum을 실행하고 파일이 이제 첨부한 것과 동일한지 확인합니다. 시간을 정하세요. 0, < 1 블록, 정확한 블록 수, 여러 블록 + 1비트 및 전체 파일을 포함한 다양한 N 값으로 테스트되었습니다.

포상금을 받으려면 코드를 작성하고 테스트해야 합니까?

답변4

당신 은 printf이것을 할 수 있습니다sed이건 매우 위험해요임시 복사본을 사용하지 않고 즉시 파일 편집이 훌륭한 기사를 읽어 보시기를 적극 권장합니다.하기 전에.

또한 파일이 너무 크고 메모리가 부족하면 실패할 수 있다는 점을 명심하세요..

printf '%s\n' "$(sed '1d' test.txt)" > test.txt

즉, 이는 inode를 변경하지 않고도 작동하고 파일을 동적으로 수정해야 합니다.

관련 정보