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
쉘에서 일어나는 일은 다음과 같습니다:
- 우리(셸)
fork()
는 하위 프로세스가 상위 프로세스(셸)로부터 열린 파일 설명자를 상속받습니다. - 하위 프로세스에서는
fopen()
"~root/log"를 (확장)하고dup2()
이를 fd 1(및close()
임시 fd)로 설정합니다.fopen()
실패할 경우exit()
부모에게 전화하여 오류를 신고하세요. - 아직 자식에서는
exec()
"./write_file.py"입니다. 이제 프로세스는 더 이상 코드를 실행하지 않습니다(실행이 실패하는 경우exit()
상위 프로세스에 오류를 보고하지 않는 한). - 상위 프로세스는
wait()
하위 프로세스를 종료하고 종료 코드를 처리하도록 합니다($?
적어도 복사).
따라서 리디렉션 은 사이의 하위 항목 에서 fork()
발생 해야 합니다. 부모는 자식의 파일 설명자에 액세스할 수 없습니다(만약 그랬더라도 stdout에 처음 쓰는 사이에 리디렉션이 발생한다는 보장은 없습니다 ).exec()
fork()
exec()
exec()
답변4
그 반대가 사실임을 말씀드리게 되어 유감입니다. 쉘은 먼저 I/O를 열고 제어권을 프로그램에 전달해야 합니다.
tee
이 경우 도움이 될 수 있습니다../write_file.py | tee -a ~root/log > /dev/null