파일을 복사하고 문자를 바꾼 다음 연결하세요.

파일을 복사하고 문자를 바꾼 다음 연결하세요.

다음과 같은 파일이 있습니다.

i36aasf5i7538i123
i47982i16537i1256
i1647i6458i3457
i1856i8456i43865

각 줄의 첫 번째 i가 o로 바뀌는 파일을 복사하고 싶습니다. 그런 다음 편집된 파일을 다시 원본 파일에 연결하려고 합니다(가급적이면 출력 파일을 지정하지 않고).

따라서 출력은 다음과 같습니다.

i36aasf5i7538i123
i47982i16537i1256
i1647i6458i3457
i1856i8456i43865
o36aasf5i7538i123
o47982i16537i1256
o1647i6458i3457
o1856i8456i43865

나는 그렇게 하는 몇 가지 단 하나의 라이너를 알고 있습니다. 그러나 sed를 사용할 때 인코딩에 문제가 발생했습니다(파일에 특이한 문자가 포함되어 있음). Perl을 사용하면 이 문제가 없지만 가능한 한 "우아하게" Perl 스크립트에 통합하는 방법을 찾고 있습니다.

저는 유닉스 운영체제를 사용하고 있습니다.

답변1

읽고 있는 파일에 데이터를 추가하면 이전에 쓴 데이터를 처리하게 되므로 무한 루프에 들어가 파일이 영원히 커질 위험이 있습니다.

다음을 통해 이를 방지할 수 있습니다.

perl -pe '
  BEGIN{seek(STDOUT,0,2);$end = tell STDOUT}
  last if tell(ARGV) > $end;
  s/i/o/' < file >> file

Perl 스크립트에서:

open OUT, ">>", "file" or die "open file: $!";
open IN, "<", "file" or die "open file: $!";
seek(OUT,0,2) or die "seek: $!";
$end = tell OUT;
while (tell IN < $end && <IN>) {
  s/i/o/;
  print OUT $_;
}
close IN;
close OUT;

답변2

sed 's/^i/o/;H;1h;$!d;x;q' <infile >>infile

파일이 메모리에 들어갈 만큼 작은 경우 위의 방법이 작동합니다. sed문제가 없는 한 인코딩 문제가 발생할 수 있는 이유를 생각할 수 없습니다 . 정상적인 사람들은 sed당신이 던지고 싶은 유효한 문자 인코딩을 처리해야 합니다.

메모리에 들어갈 만큼 작지 않다면 다음을 이해하는 시스템에서/dev/fd/[num]링크(실제로 모든 Unix 계열 시스템), 파이프 대신 tmp 파일을 문서로 사용하는 쉘이 제공됩니다.(대부분 Bourne 쉘을 포함 bash하지만 zshBSD 및 기타 변형은 제외 yash되거나 대신 파이프를 사용합니다)ashshdashbusybox sh${TMPDIR:-/tmp}, 편집 중인 버퍼를 수용할 수 있는 충분한 여유 공간이 있으면 다음이 작동합니다.

sed -nf- file <<"" >>file
s/^i/o/
w /dev/fd/0
$r /dev/fd/0

이것은 쉘이 임시 파일과 문서의 파일 설명자를 여기에서 가져오고 여기 sed에 스크립트를 작성하기 때문에 작동합니다. unlink()즉, 임시 파일(따라서 파일 시스템에서 유일한 링크 제거), 그런 다음 이를 상속하는 하위 항목으로 분기 sed하고 자체 상태를 호출 전 상태로 복원하여 sed자체 설명자를 임시 파일에 넣습니다. 이 시점에서 파일은 sedstdin 설명자로만 존재하며 커널은 파일에 대한 핸들이 존재하는 한 파일을 유지해야 하지만 모든 설명자가 해제되면 파일 시스템 0과의 파일 링크가 제거됩니다.

따라서 sed삭제된 임시 파일에서 스크립트를 읽은 -f다음 w이름이 지정된 rite 파일로 잘라냅니다. 이는 스크립트를 읽는 삭제된 파일에 대한 링크일 뿐입니다. 작성할 각 입력 줄을 추출하기 전에 다음의 복사본을 입력합니다. 패턴 공간입니다. sed자동으로 무엇이든 인쇄 -n하지만 $마지막 입력 행 에서는 r표준 출력에 기록했던 파일을 기록 하고 해당 파일은 명명된 편집 항목에 추가 w됩니다.>>file.

완료 되고 sed해당 프로세스가 종료되면 <<""here-doc 소스의 마지막 남은 설명자가 닫히고 커널은 이후에 파일을 정리합니다. 동시에 다른 프로세스는 어떤 방식으로든 파일에 액세스할 수 없으므로 sed다른 프로세스가 어떤 방식으로든 작업 버퍼에 영향을 미칠 가능성에 영향을 받지 않습니다.

작동하지 않는다면 -nf-아마도 stdin으로 sed해석하지 않았기 때문일 것입니다.-(대부분은 그렇지만)을 사용해야 합니다 -nf/dev/fd/0.

답변3

파일의 초기 크기로 제한된 파일에 제한된 메모리 맵을 생성하여 메모리 매핑을 사용하여 "속임수"할 수 있습니다. 파일에 대한 다른 핸들을 별도로 열고 끝에서 해당 핸들을 찾으십시오. 메모리 맵에 대한 반복을 시작하여 읽은 각 줄을 파일 끝에 있는 다른 파일 핸들에 씁니다. 대표 python코드

import mmap
with open('file', 'r+') as f1, open('file', 'r+b')  as f2:
    mm = mmap.mmap(f2.fileno(), 0) #memory map restricted to current file length
    f1.seek(0, 2) #seek to end of file
    for line in mm:
            f1.write(line.replace('i', 'o', 1))

관련 정보