방금 큰(기가바이트) 크기의 파일에서 일부 줄을 잘라야 하는 문제에 직면했고, 메모리에서 이 파일을 읽으려고 시도하는 잠재적인 CPU 비용을 알고 대신 그 자리에서 편집하고 싶었습니다. 다음과 같은 질문이 나왔습니다.
...그리고 또한 다음도 있습니다:
ext3
그러나 나는 뭔가 다른 것에 대해 방황하고 있었습니다. 나는 어떤 파일 시스템(예 : )이 파일의 조각과 같은 것을 설명할 수 있으려면 연결된 목록과 같은 것을 사용해야 한다고 믿습니다(그러나 확실하지는 않습니다). 디스크 영역에 매핑됩니다.
따라서 다음과 같은 작업을 수행하는 것이 가능해야 합니다. 예를 들어 다음과 같은 파일이 있다고 가정해 보겠습니다 bigfile.dat
(숫자는 바이트 오프셋을 나타내야 하지만 정렬하기가 약간 어렵습니다).
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
L 1\n L 2\n L 3\n L 4\n L 5\n L 6\n
그런 다음 이 파일은 원칙적으로 검색을 위해 터미널 애플리케이션에 로드될 수 있습니다. 도구를 호출한다고 가정 하고 동일한 파일(줄 번호 포함)을 표시하는 editsegments bigfile.dat
방법과 유사하다고 가정해 보겠습니다 .less -N bigfile.dat
1 1 L 1
2 2 L 2 *
3 3 L 3
4 4 L 4 *
5 5 L 5
6 6 L 6
bigfile.dat (END)
예를 들어, 여기에 명령을 입력하고(예 d
: 줄 삭제) 다른 키를 클릭하거나 위에 표시된 위치에서 마우스를 클릭할 수 있습니다. 즉 *
, 줄 2와 4 사이의 모든 내용이 삭제되어야 한다는 의미입니다. 그러면 프로그램은 다음과 같이 응답합니다.
1 1 L 1
2 5 L 5
3 6 L 6
bigfile.dat (END)
이제 가장 왼쪽 첫 번째 열에는 "새" 줄 번호(잘라내기 전)가 표시되고, 두 번째 열에는 "오래된" 줄 번호(잘라내기 전)가 표시되며 실제 줄 내용이 뒤따르는 것을 볼 수 있습니다.
이제 이 의사 응용 프로그램이 종료된 후에 발생한다고 상상하는 것은 editsegments
무엇보다도 그대로 bigfile.dat
유지된다는 것입니다. 그러나 이제 동일한 디렉토리에 추가 텍스트 파일도 있을 것입니다 bigfile.dat.segments
. 다음 내용으로:
d 4:15 # line 2-4
... 그리고 추가로 ("symlink"와 같은) 특수 파일("symlink"라고 부르겠습니다 bigfile.dat.iedit
)이 나타날 것입니다.
bigfile.dat.iedit
이제 기본적으로 이 모든 것의 결과는 이제 와 같은 것으로 열려고 하면 less -N bigfile.dat.iedit
"편집된" 내용을 얻고 싶을 것입니다.
1 L 1
2 L 5
3 L 6
bigfile.dat (END)
$FILE.iedit
... 이것은 열릴 때 먼저 $FILE.segments
열어서 읽어야 한다고 운영 체제에 지시함으로써 달성될 수 있을 것 같습니다 . 그러면 d 4:15
원본 파일의 바이트 4~15를 제외해야 한다고 지시합니다. 결과는 다음과 같습니다.
0 1 2 3 4 5 6 7 8 9 10 11 12,3,4 15 16 17 18 19 20 21 22 23
L 1\n
L
2
\n
L
3
\n
L
4
\n
L 5\n
L 6\n
0 1 2 3 ------------------>16 17 18 19 20 21 22 23
다시 말해서 -가정파일의 파일 시스템 개념에서 콘텐츠의 각 바이트에는 체인의 다음 바이트에 대한 "링크"도 포함되어 있습니다. 스크립트를 기반으로 새 연결 목록을 설정하고 콘텐츠를 제공하도록 파일 시스템에 지시할 수 있어야 합니다. 특수 파일(symlink 또는 파이프)을 통해 이 수정된 연결 목록으로 표시됩니다.
이것이 제가 제목에서 "스크립트를 썼다"는 의미입니다. "새" 연결 목록은 스크립트 파일( $FILE.segments
)에 의해 제어될 수 있고 텍스트 편집기에서 사용자가 편집할 수 있습니다(또는 프런트 엔드 애플리케이션에 의해 생성됨). 내가 의미하는 "멀티패스"는 bigfile.dat
이 프로세스에서 전혀 수정되지 않는다는 사실입니다 . 그래서 오늘 첫 번째(원본) 기가바이트를 편집하고 ( $FILE.segments
)에 진행 상황을 저장할 수 있습니다. 그런 다음 내일 두 번째 기가바이트를 편집하고 ( )에 진행 상황을 다시 저장할 수 있습니다 $FILE.segments
. - 그동안 원본은 bigfile.dat
변경되지 않았습니다.
모든 편집이 완료되면 일종의 명령(예: editsegments --finalize bigfile.dat
)을 호출할 수 있습니다. 이 명령은 새 연결 목록을 의 내용으로 bigfile.dat
(그리고 이에 따라 제거 bigfile.dat.segments
및 bigfile.dat.iedit
) 영구적으로 인코딩합니다. 아니면 더 쉽게 다음과 같이 할 수도 있습니다.
cp bigfile.dat.iedit /path/to/somewhere/else/bigfile.modified.dat
물론 elete 스크립트 명령 외에도 다음과 같은 eplace 명령도 d
있을 수 있습니다 .r
r 16:18 AAA
... 말하기: 바이트 16과 18 사이의 내용을 공백 뒤의 다음 18-16+1=3바이트로 대체합니다(즉, AAA
) - 연결된 목록은 실제로 스크립트 명령 내용 자체에 "연결"될 수 있습니다( 아래 차트에는 d
엘레테도 포함되어 있습니다):
0 1 2 3 4 5 6 7 8 9 10 11 12,3,4 15 16 17 18 19 20 21 22 23
L 1\n
L
2
\n
L
3
\n
L
4
\n
L
5
\n
L 6\n
0 1 2 3 ------------------>| | 19 20 21 22 23
.
.
.
.
.
.
.
\n
r
1
6
:
1
8
AAA
\n
.
.
.
.
이제 내 생각엔 다음과 같은 프로그램이 hexedit
(언급했듯이)여기) 그 자리에서 파일을 변경합니다. 하지만 스크립팅 가능성의 이점(터미널 응용 프로그램이라도 GUI 응용 프로그램으로 규제할 수 있다면 더 좋습니다)과 실제로 원본 파일이 없다는 이점을 원합니다. 모든 편집이 필요하다는 것을 확인할 때까지 변경됩니다.
이와 같은 것이 가능한지 확실하지 않습니다. 설사 가능하더라도 (단순한 사용자 프로그램이 아닌) 전용 드라이버가 필요할 수도 있습니다... 하지만 어쨌든 물어볼 가치가 있다고 생각합니다. 거기에 있습니까? 리눅스에 이런 게 있나요?
답변해 주셔서 미리 감사드립니다.
건배!
답변1
디스크의 파일 구조는 사용 중인 파일 시스템에 따라 다릅니다. 실제 파일 시스템 중 어느 것도 귀하가 설명하는 대로 연결 목록을 사용하지 않습니다(그러면 fseek(3)
견딜 수 없게 됩니다). 이에 가장 가까운 것은 Microsoft의 것입니다.지방, 기본적으로 포인터를 데이터 블록에서 이를 가리는 배열로 이동합니다.
그러나 대부분의 파일 시스템은 파일의 데이터 블록에 대한 포인터 기반 참조를 사용하므로 원칙적으로 전체 파일 내용이 아닌 포인터 몇 개를 섞고 블록을 표시하여 파일 블록을 잘라낼 수 있습니다. 파일의 중간은 무료입니다. 안타깝게도 이는 별로 유용한 작업이 아닙니다. 파일 블록은 다소 크고(일반적으로 4KiB) 파일의 구조(라인 또는 기타 하위 구분)와 합리적으로 정렬되는 경우가 거의 없습니다.
답변2
당신이 묘사하는 것은 다음과 매우 유사하게 들립니다.다시 하다텍스트 편집기의다시 실행 목록변경되지 않은 원본 파일에 대해다시 실행 목록속합니다. 나는 gvim
그런 것이 있다고 확신한다.지속적인실행 취소/다시 실행 목록(?)을 활용할 수 있으며, emacs
(스크립트를 통해) 원하는 것은 무엇이든 하도록 유도할 수 있는 목록이 확실히 있다는 것을 알고 있습니다 elisp
.세션 간 Emacs 실행 취소 기록 저장.
참고로, 다음과 같은 대용량 파일의 경우 원치 않는 작업을 모두 끄는 것이 좋습니다.자동 저장,구문 강조(천천히큰emacs 파일) 등.. 32비트 시스템의 emacs는 256MB입니다.파일 크기 제한.
제안한 것만큼 간결하지는 않지만 변경 사항이 많지 않은 경우에는 사용할 수 있습니다.
답변3
일반적으로 전체 파일을 메모리로 가져오지 않으면 파일을 편집할 수 없습니다. 나는 당신이 실제로하고 싶은 일은 특정 줄이없는 이전 파일의 복사본 인 새 파일을 갖는 것이라고 가정합니다. 이는 유닉스 유틸리티 head
와 tail
. 예를 들어, 파일에서 5, 12, 52행을 제외한 모든 내용을 복사하려면 다음을 수행하십시오.
head -n 4 bigfile.dat > tempfile.dat
tail -n +6 bigfile.dat | head -n 6 >> tempfile.dat
tail -n +13 bigfile.dat | head -n 39 >> tempfile.dat
tail -n 53 bigfile.dat >> tempfile.dat
이러한 유틸리티에 대해 잘 모르시는 경우를 대비해 더 자세히 설명하겠습니다.
유틸리티 head
는 파일에서 처음 n줄을 인쇄합니다. 위치 인수가 제공되지 않으면 표준 입력을 파일로 사용합니다. 플래그 -n
는 인쇄할 라인 수를 머리에 알려줍니다. 따라서 head -n 2
표준 입력에서 처음 2줄만 인쇄합니다.
유틸리티 tail
는 파일의 마지막 n줄을 인쇄합니다. head와 마찬가지로 파일이나 표준 입력에서 읽을 수 있습니다. -n 플래그는 tail 끝에서 인쇄할 줄 수를 알려줍니다. 숫자 앞에 더하기 기호를 붙여서 tail이 처음부터 해당 행부터 시작하여 파일 끝의 행을 인쇄하도록 할 수도 있습니다. 예를 들어 tail -n 2
표준 입력에서 마지막 두 줄을 인쇄합니다. 그러나 tail -n +2
라인 번호 2로 시작하는 모든 라인을 인쇄합니다(라인 1 생략).
따라서 일반적으로 파일에서 [x, y) 범위의 행을 인쇄하려면 다음을 수행하십시오.
`tail -n +x | head -n d`
여기서 d = y - x입니다. 이 명령은 새 파일을 생성합니다. 원하는 경우 이전 파일을 삭제할 수 있습니다. 이 방법의 장점은 head
한 tail
번에 한 줄만 메모리에 유지하면 되므로 RAM이 빨리 채워지지 않는다는 것입니다.
답변4
sed 스크립트 작업처럼 들립니다. IIRC는 이러한 작업을 위해 설계되었습니다. 한 줄씩 처리, 동일한 명령 그룹의 반복 처리 및 정규 표현식이 모두 하나의 도구에 결합됩니다. 나는 그것이 일을 할 것이라는 것을 알고 있지만, 당신에게 벌금을 부과하는 것 외에는 더 이상 안내할 수 없습니다.매뉴얼 페이지.