리디렉션이 실패하면 Bash 프로그램이 실행되지 않습니다.

리디렉션이 실패하면 Bash 프로그램이 실행되지 않습니다.

Bash에서 리디렉션을 사용하는 명령이 실패하면 해당 명령 이전에 실행 중이던 모든 프로그램이 실행되지 않는 것으로 나타났습니다.

예를 들어, 이 프로그램은 "a" 파일을 열고 "a" 파일에 50바이트를 씁니다. 그러나 이 명령을 실행하고 권한이 부족한 파일(~root/log)로 리디렉션해도 "a"의 파일 크기는 변경되지 않습니다.

$ ./write_file.py >> ~root/log
-bash: /var/root/log: Permission denied
cdal at Mac in ~/experimental/unix_write
$ ls -lt
total 16
-rw-rw-r--  1 cdal  staff  0 Apr 27 08:54 a <-- SHOULD BE 50 BYTES

프로그램이 실행되어 출력을 캡처한 다음(파일 "a"에도 쓰기) ~root/log에 출력을 쓰지 못할 것이라고 생각할 수 있습니다. 대신 프로그램이 실행되지 않습니다.

왜 이런 일이 발생합니까? bash는 프로그램을 실행하기 전에 "검사"가 수행되는 순서를 어떻게 선택합니까? 다른 테스트도 수행됩니까?

ps. "권한 거부" 파일로 리디렉션될 때 cron에서 실행 중인 프로그램이 실제로 실행되고 있는지 확인하려고 합니다.

답변1

이는 실제로 검사 순서에 대한 문제가 아니라 단지 셸 설정의 순서에 대한 문제입니다. 리디렉션은 명령이 실행 ~root/log되기 전에 설정됩니다. 따라서 로그 파일을 열 수 없으므로 예제에서는 쉘이 ./write_file.py명령줄 처리를 중지합니다.

이를 입증하는 한 가지 방법은 실행 불가능한 파일을 가져와서 실행해 보는 것입니다.

$ touch demo
$ ./demo
zsh: permission denied: ./demo
$ ./demo > ~root/log
zsh: permission denied: /root/log

이는 쉘이 ./demo리디렉션을 설정할 수 없는 경우도 고려하지 않음을 보여줍니다.

답변2

~에서Bash 매뉴얼 페이지, 리디렉션 섹션(내 강조점):

앞으로명령을 실행할 때 셸에서 해석되는 특수 기호를 사용하여 입력과 출력을 리디렉션할 수 있습니다.

...

파일을 열거나 생성하지 못하면 리디렉션이 실패합니다.

그래서 쉘은 대상 파일을 열려고 시도 stdout하지만 실패하고 명령이 전혀 실행되지 않습니다.

답변3

껍질을 관찰할 가치가 있다~ 해야 하다프로그램을 시작하기 전에 리디렉션을 설정하십시오.

귀하의 예를 고려하십시오.

./write_file.py >> ~root/log

쉘에서 일어나는 일은 다음과 같습니다:

  1. 우리(셸) fork()는 하위 프로세스가 상위 프로세스(셸)로부터 열린 파일 설명자를 상속받습니다.
  2. 하위 프로세스에서는 fopen()"~root/log"를 (확장)하고 dup2()이를 fd 1(및 close()임시 fd)로 설정합니다. fopen()실패할 경우 exit()부모에게 전화하여 오류를 신고하세요.
  3. 아직 자식에서는 exec()"./write_file.py"입니다. 이제 프로세스는 더 이상 코드를 실행하지 않습니다(실행이 실패하는 경우 exit()상위 프로세스에 오류를 보고하지 않는 한).
  4. 상위 프로세스는 wait()하위 프로세스를 종료하고 종료 코드를 처리하도록 합니다( $?적어도 복사).

따라서 리디렉션 은 사이의 하위 항목 에서 fork()발생 해야 합니다. 부모는 자식의 파일 설명자에 액세스할 수 없습니다(만약 그랬더라도 stdout에 처음 쓰는 사이에 리디렉션이 발생한다는 보장은 없습니다 ).exec()fork()exec()exec()

답변4

그 반대가 사실임을 말씀드리게 되어 유감입니다. 쉘은 먼저 I/O를 열고 제어권을 프로그램에 전달해야 합니다.

tee이 경우 도움이 될 수 있습니다../write_file.py | tee -a ~root/log > /dev/null

관련 정보