파일에 다른 스트림을 추가하는 것이 안전한 이유는 무엇입니까?

파일에 다른 스트림을 추가하는 것이 안전한 이유는 무엇입니까?

cmd >out_err.txt 2>out_err.txt다음 예와 같이 표준 출력과 오류를 동일한 파일로 리디렉션하면 데이터가 손실될 수 있는 것으로 알려져 있습니다 .

work:/tmp$ touch file.txt
work:/tmp$ ls another_file.txt
ls: cannot access 'another_file.txt': No such file or directory

위는 예제의 설정 코드입니다. 빈 파일이 file.txt존재하며 another_file.txt사물이 아닙니다. 아래 코드에서는 out_err.txt이러한 파일을 나열하는 운영 체제로 입력 및 출력을 순진하게 리디렉션합니다.

work:/tmp$ ls file.txt another_file.txt >out_err.txt 2>out_err.txt
work:/tmp$ cat out_err.txt 
file.txt
t access 'another_file.txt': No such file or directory

오류 스트림에 일부 문자가 누락된 것을 볼 수 있습니다. 그러나 >>valid를 사용하면 예제를 복제한다는 의미에서 전체 출력과 전체 오류가 보존됩니다.

왜 그리고 어떻게 cmd >>out_err.txt 2>>out_err.txt작동합니까?

답변1

잘 알려져 있는지는 확실하지 않지만 이렇게 하면 두 파일 핸들이 완전히 독립적이고 독립적인 읽기/쓰기 위치를 갖기 때문에 발생합니다. 그래서 그들은 서로를 덮을 수 있습니다. (그들은 서로 다른 두 가지에 해당합니다.파일 설명 열기, 불행하게도 "파일 설명자"라는 용어와 쉽게 혼동될 수 있는 기술 용어를 사용합니다. )

foo > out.txt 2>out.txt대신에 foo > out.txt 2>&1이는 파일 설명자(동일한 열린 파일 설명 참조)를 복사하기 때문에 발생합니다 .

첨부할 때,모두 쓰다작성된 파일의 끝으로 이동합니다. 이는 운영 체제에 의해 원자적으로 처리되므로 다른 프로세스도 개입할 수 없습니다. 따라서 독립적인 읽기/쓰기 위치 문제가 해결되었습니다. (단, 파일 시스템의 한계인 NFS에서는 작동하지 않을 수 있습니다.)

귀하의 예에서는 오류 메시지가 ls: cannot access...먼저 파일 시작 부분에 기록됩니다. stderr fd의 쓰기 위치는 이제 파일 끝에 있습니다. 그런 다음 일반 출력 file.txt<newline>도 기록되지만 stdout fd의 쓰기 위치는 여전히 시작 부분에 있으므로 이 9바이트는 오류 메시지의 일부를 포함합니다.

fd가 첨부되면 무슨 일이 일어나더라도 두 번째 쓰기가 종료됩니다.

답변2

단순 리디렉션은 (2) 빈 파일을 생성하고 파일 위치를 첫 번째 바이트에 배치하는 O_CREAT 및 O_TRUNC 옵션을 사용하여 파일을 엽니다.

파일을 추가하면 O_APPEND 옵션으로 파일이 열립니다. 이 옵션을 사용하면 각 쓰기 작업 전에 파일의 현재 끝을 찾을 수 있습니다.

~에서man 2 open

    O_APPEND
          The file is opened in append mode.  Before  each  write(2),  the
          file  offset  is  positioned  at the end of the file, as if with
          lseek(2).  The modification of the file offset and the write op‐
          eration are performed as a single atomic step.

즉, 커널은 추가가 다음과 충돌하지 않도록 보장합니다.

관련 정보