파일을 내부 수정하는 방법은 무엇입니까?

파일을 내부 수정하는 방법은 무엇입니까?

파일의 "내부" 수정(예: sed -i또는 를 통해) 은 무엇을 perl -i의미합니까?
내 질문은 이 내부 수정을 수행하는 방법입니다. 파일을 복사하고 복사본을 변경한 다음 원본을 바꾸시나요? 아니면 원본 파일을 적절하게 수정했나요?

답변1

sed임시 파일을 만들고 파일에 출력을 쓴 다음 원본 파일을 기반으로 임시 파일의 이름을 바꿉니다.

다음을 사용하여 무슨 일이 일어나는지 관찰할 수 있습니다.strace:

$ strace -e trace=file sed -i -e '' a
execve("/usr/bin/sed", ["sed", "-i", "-e", "", "a"], [/* 34 vars */]) = 0
<...trimmed...>
open("a", O_RDONLY)                     = 3
open("./sedxvhRY8", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
rename("./sedxvhRY8", "a")              = 0
+++ exited with 0 +++

이는 모든 파일 작업을 기록합니다 sed. 새 파일(사용하기에 안전한 O_CREAT|O_EXCL)을 생성하고 여기에 데이터를 쓴 다음 원래 파일의 맨 위로 다시 이동합니다 a.

sed -i백업용 접미사를 허용합니다. 이 경우 원본 파일을 먼저 이동합니다(맨 위에서 이름을 바꾸는 대신). 이 매개변수는 대부분의 BSD에서 필수입니다 sed. 이 경우 디렉터리에 올바른 이름의 파일이 잠시 존재하지 않습니다.

perl최신 버전에서 입력 파일을 연 다음 삭제하고 동일한 이름의 새 파일을 만듭니다.

open("a", O_RDONLY)               = 3
unlink("a")                       = 0
open("a", O_WRONLY|O_CREAT|O_EXCL, 0600) = 4

삭제하면 (unlink) 이미 파일을 열었다면 핸들을 유지하는 한 해당 파일에 대한 액세스 권한을 유지하므로 삭제된 파일에서 데이터를 계속 읽을 수 있습니다. 이 방법을 사용하면 perl출력 파일이 임시 파일이 아닌 직접 작성됩니다. 추가 파일이 생성되지 않지만 프로세스 중에 파일을 읽으면 with의 sed방법과 달리 부분적인 내용을 얻게 됩니다. 또한 올바른 이름의 파일이 없는 짧은 기간이 있는데, 이는 프로세스 끝이 아닌 시작 부분에 있습니다(그림 참조 sed -i .bak).


둘 다 sedperl둘 다:

  • 심볼릭 링크를 일반 파일로 바꿉니다.
  • 하드 링크를 끊습니다.
  • 가능하다면 그룹 소유권을 유지하세요.
  • setgid파일이 귀하가 속하지 않은 그룹에 속하고 귀하가 루트가 아닌 경우 파일은 기본 그룹(또는 디렉토리에 해당 비트가 있는 경우 상위 디렉토리의 그룹)을 사용하여 생성됩니다.
  • 루트인 경우 파일 소유권을 유지하십시오.
  • 기본 권한을 유지하세요.
  • 저장 setuid하고 setgrp비트,만약에결과 그룹은 시작된 그룹과 동일합니다.
  • 끈끈한 부분을 유지하세요.
  • 아니요xattrs가 예약되었습니다.

sed할 것이다:

  • ACL을 보존합니다 (Linux의 경우, 다른 경우는 잘 모르겠습니다) .

perl할 것이다:

  • 아니요ACL을 유지하세요.

위의 내용은 GNU를 사용하는 Linux sed와 FreeBSD 파생 제품을 사용하는 Mac OS X 모두에 적용됩니다 sed.

답변2

@Homer의 답변 외에도 다음과 같은 내용이 있습니다 perldoc perlrun.

"<>" 구문으로 처리된 파일이 제자리에서 편집되도록 지정합니다. 입력 파일의 이름을 바꾸고, 원래 이름으로 출력 파일을 열고, 해당 출력 파일을 print() 문의 기본 파일로 선택하여 이를 수행합니다. 확장자(제공된 경우)는 다음 규칙에 따라 백업 복사본을 만들기 위해 이전 파일의 이름을 수정하는 데 사용됩니다.

확장자가 제공되지 않으면 백업이 이루어지지 않고 현재 파일을 덮어씁니다.

확장자에 *가 포함되어 있지 않으면 현재 파일 이름 끝에 접미사로 추가됩니다. 확장자에 하나 이상의 * 문자가 포함되어 있으면 각 *가 현재 파일 이름으로 대체됩니다.

소프트 또는 하드 링크는 유지되지 않습니다.

-i는 동일한 이름의 새 파일을 만들기 전에 원본 파일의 이름을 바꾸거나 삭제하므로 UNIX 스타일 소프트 링크와 하드 링크는 유지되지 않습니다.

마지막으로 -i 스위치는 명령줄에 파일이 제공되지 않을 때 실행을 차단하지 않습니다. 이 경우 백업이 이루어지지 않으며(물론 원본 파일을 확인할 수 없음) 예상대로 STDIN에서 STDOUT으로 처리가 계속됩니다.

-i이는 또한 with 옵션을 사용해야 하는 이유 -p또는 print내부 편집을 원하는 경우 명시적 명령문을 사용해야 하는 이유를 설명합니다 perl.

# Opps, file will be truncated, becomes empty
$ perl -i.bak -ne 's/123/qwe/' file

# Right way
$ perl -i.bak -ne 's/123/qwe/;print' file

# Or
$ perl -i.bak -pe 's/123/qwe/' file

관련 정보