for 루프의 일부로 동일한 파일에 쓰면 빈 파일이 생성됩니다.

for 루프의 일부로 동일한 파일에 쓰면 빈 파일이 생성됩니다.

특정 패턴과 일치하는 여러 파일에 일부 텍스트를 추가하는 명령을 작성 중입니다.

for file in $(find . -name "*.txt"); do sed "1s/^/hello/" $file; done 

stdout다른 파일(예 : ) 에 쓰면 "$file.bak"모든 것이 계획대로 진행되지만 명령을 사용하여 동일한 파일에 다시 쓰려고 하면 파일 내용이 지워집니다.

for file in $(find . -name "*.txt");do sed "1s/^/hello/" $file > $file; done

나는 이 동작이 놀랍다고 생각합니다. 왜 이런 일이 발생하는지 개념적으로 설명할 수 있는 사람이 있습니까? 나는 동일한 효과 bash로 macOS에서 이것을 시도했습니다 .zsh

(나는 sed -i ""제자리에 쓰는 것에 대해 알고 있지만, 제자리에 쓰기 전에 결과를 다른 명령으로 파이프하고 싶습니다.)

답변1

개념적 놀라움은 이 진술에 있을 수 있습니다.

하지만 동일한 파일에 명령을 다시 쓰려고 하면

사용하면 다시 쓰기 위해 파일을 여는 cmd file > file대신 cmd셸 자체를 엽니다. 이를 발견했을 때 쉘이 가장 먼저 하는 일은 > file쓰기 모드로 위치 0에서 파일을 열고(따라서 파일이 잘림) stdout을 파일로 리디렉션하는 것입니다. 따라서 cmd읽기 시작하는 순간 file이미 비어 있습니다.

또는 더 공식적으로는 다음과 같습니다.

  • cmdShell은 실행할 새 프로세스를 분기합니다.
  • 새 프로세스(여전히 실행 중인 쉘 코드)가 file위치 0에 쓰기 위해 열립니다(따라서 잘림).
  • 새로운 프로세스 실행은 cmd실제로 현재 프로세스 내에서 새로운 바이너리를 시작합니다.
  • cmd런타임 표준 출력은 다음을 가리킵니다.file
  • cmd읽기 위해 열었 file지만 지금은 비어 있습니다.

반면, sed -i '1s/^/hello/' file별도로 관리되는 파일을 사용하는 경우 sed(기술적으로는 백그라운드에 임시 파일을 생성합니다.)

관련 정보