파일 출력을 자체로 리디렉션하면 왜 빈 파일이 생성됩니까?


19

파일 출력을 자체로 리디렉션하면 왜 빈 파일이 생성됩니까?

Bash에 명시된 이유는 무엇입니까?

less foo.txt > foo.txt

fold foo.txt > foo.txt

빈 생산 foo.txt? 와 같은 추가 less eggs.py >> eggs.py는에서 두 개의 텍스트 사본을 eggs.py생성하므로 덮어 쓰기로 인해 하나의 텍스트 사본이 생성 될 것으로 예상 할 수 있습니다.

나는 이것이 버그라고 말하는 것이 아니라 유닉스에 관한 깊은 것에 대한 포인터 일 가능성이 큽니다.


답변:


20

을 사용 >하면 파일이 잘림 모드로 열리므로 명령이 파일을 읽으려고 시도하기 전에 내용이 제거됩니다.

을 사용 >>하면 파일이 추가 모드로 열리므로 기존 데이터가 유지됩니다. 그러나이 경우 입력 및 출력과 동일한 파일을 사용하는 것은 여전히 ​​위험합니다. 파일이 읽기 입력 버퍼 크기에 맞지 않을만큼 충분히 큰 경우 파일 시스템이 가득 찰 때까지 (또는 디스크 할당량에 도달 할 때까지) 크기가 무한대로 커질 수 있습니다.

적절한 수정을 지원하지 않는 명령으로 파일을 입력 및 출력으로 사용하려면 몇 가지 해결 방법을 사용할 수 있습니다.

  • 유틸리티를 실행하는 동안 오류가 발생하지 않은 경우에만 중간 파일을 사용하여 원본 파일을 덮어 씁니다 (이 방법이 가장 안전하고 일반적인 방법 임).

    fold foo.txt > fold.txt.$$ && mv fold.txt.$$ foo.txt
  • 오류나 중단이 발생할 경우 잠재적 인 부분적 또는 완전한 데이터 손실을 희생하여 중개 파일을 피하십시오. 이 예에서 파일의 내용은 파일이 삭제 되기 전에 괄호 안에 foo.txt있는 서브 쉘에 입력으로 전달 됩니다. 서브 쉘이 데이터를 읽는 동안 서브 쉘이 열린 상태로 유지되므로 이전 inode는 활성 상태를 유지합니다. 내부 유틸리티 (여기서 )가 동일한 이름 (foldfoo.txt)는 이전 디렉토리 항목이 기술적으로 제거 되었기 때문에 다른 inode를 가리 킵니다. 프로세스 중에 동일한 이름을 가진 두 개의 다른 "파일"이 있습니다. 서브 쉘이 종료되면 이전 inode가 해제되고 해당 데이터가 손실됩니다. 이전 파일과 새 파일을 동시에 임시로 저장할 수있는 충분한 공간이 있는지 확인하십시오. 그렇지 않으면 데이터가 손실됩니다.

    (rm foo.txt; fold > foo.txt) < foo.txt

3
spongemoreutils 에서 도움이 될 수도 있습니다. fold foo.txt | sponge foo.txt– 또는 fold foo.txt | sponge !$해야합니다.
slhck

@slhck 실제로, 스폰지도 그 일을 할 수있었습니다. 그러나 POSIX 또는 OS와 같은 유닉스에서는 주류로 지정되지 않았으므로 존재하지 않을 것입니다.
jlliagre

이 할 수없는 것은 아니다 만든 하지만 현재)
slhck


0

bash에서 스트림 재 지정 연산자 는 왼쪽 피연산자를 평가하기 전에... > foo.txt 비 웁니다 .foo.txt

명령 대체를 사용하고 결과를 임시 해결책으로 인쇄 할 수 있습니다. 이 솔루션은 다른 답변보다 문자 수가 적습니다.

printf "%s\n" "$(less foo.txt)" > foo.txt

주의 :이 명령은에서 줄 바꿈 개행을 유지하지 않습니다 foo.txt. 자세한 내용은 아래 주석 섹션을 참조하십시오

여기서, 서브 쉘 $(...)은 스트림 재 지정 연산자 이전 에 평가 >되므로 정보의 보존이다.


@KamilMaciorowski : 실제로는 tmp=$(cmd; printf q);  printf '%s' "${tmp%q}"입니다. 그러나이 답변에서 또 다른 문제를 놓쳤습니다.“명령 대체”를 의미 할 때“서브 쉘”이라고 말합니다. 예, 명령 대체는 일반적으로 서브 쉘이지만 그 반대는 아니며 서브 쉘은 일반적으로이 문제에 도움이되지 않습니다.
스콧

@KamilMaciorowski 나는이 모든 것을 놓친 것에 대해 너무 나쁘게 느낀다. 이 모든 것을 지적 해 주셔서 감사합니다. 네 번째 요점 : 역 따옴표가 트릭을 수행합니까, 즉 후행 줄 바꿈을 유지합니까?
Louis-Jacob Lebel

답장을 보내 주셔서 감사합니다. "명령 대체"에 대해 "서브 쉘"을 변경했습니다. 그건 그렇고, 나는 두 사람의 정확한 차이점이 무엇인지 궁금합니다.
Louis-Jacob Lebel

아니요, 역 따옴표 (backticks)는 후행 줄 바꿈 문자도 제거합니다.
Kamil Maciorowski

좋아, 나는 지금 경고 메시지를 추가했다. 해결책을 찾으면 제거하겠습니다.
Louis-Jacob Lebel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.