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


9

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는 프로그램을 실행하기 전에 수행하는 "검사"순서를 어떻게 선택합니까? 다른 점검도 수행됩니까?

추신 : cron에서 실행되는 프로그램이 "permission denied"파일로 리디렉션 될 때 실제로 실행되었는지 확인하려고합니다.


모든 것이 잘 작동합니다 (즉, .py 파일의 소유권 및 권한) 프로그램이 정상적으로 실행됩니다. 문제는 리디렉션에서 발생합니다. filein / root 디렉토리에 쓸 수있는 권한이 없습니다. 그리고 당신은 stdout정확하게 그렇게하도록 리디렉션 했습니다. 따라서 프로그램이 실행 되더라도 출력이 표시되지 않습니다.
MelBurslan

2
멜, 그건 사실이 아니야, 프로그램은 실제로 실행되지 않았다. 아래 답변을 참조하십시오.
Charlie Dalsass

" write_file.py프로그램을 실행 하고 출력을 ~root/logbash로 보냅니다 :"죄송 합니다만, 그 파일에 쓸 수 없습니다! "쉘은 정확히해야 할 일을하고 있습니다. 요청한 것을 수행 할 수 없다면 문제가 발생하는 이유를 즉시 알려 주어 문제를 처리하는 방법을 결정할 수있는 기회를 제공합니다 모든 배쉬 관리자는 아는 것처럼 명령을 실행하고 출력을 저장하지 않으면 매우 나쁜 일이 발생할 수 있습니다. 저장 장소를 지정하는 것이 중요하다면 ASS | U | ME에게 잘못 될 것입니다. stdout을 저장하지 않고 실행해도 괜찮습니다
Monty Harder

답변:


18

실제로는 주문 확인의 문제가 아니라 단순히 쉘이 설정하는 순서입니다. 명령이 실행되기 전에 리디렉션이 설정됩니다. 따라서 귀하의 예에서 쉘 ~root/log은 관련 작업을 수행하기 전에 추가를 위해 열려고 시도합니다 ./write_file.py. 로그 파일을 열 수 없으므로 리디렉션이 실패하고 셸이 해당 시점에서 명령 줄 처리를 중지합니다.

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

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

이것은 쉘이 ./demo리디렉션을 설정할 수없는 시점 조차 보지 못함을 보여줍니다 .


와우, 그렇게 간단합니까? 리디렉션이 먼저 완료되었음을 알지 못했습니다. 이 답변과 다른 훌륭한 답변에 감사드립니다.
Charlie Dalsass

6
그들이 먼저 수행되지 않은 경우, 출력은 어디에 기록됩니까?
Charles Duffy

출력을 쓸 수 없다면 명령을 실행하는 것이 안전하다는 것을 어떻게 알 수 있습니까? 이 명령은 데이터 저장소에서 삭제되는 정보를 출력 할 수 있으므로 출력을 캡처해야합니다. bash는 이러한 권한을 수정하기 전까지는 실행되지 않습니다.
Monty Harder

11

로부터 bash는 남자 페이지, 섹션 재 (내게로 강조) :

명령이 실행 되기 전에 셸이 해석하는 특수 표기법을 사용하여 입력 및 출력을 리디렉션 할 수 있습니다.

...

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

따라서 쉘은의 대상 파일을 열려고 시도 stdout하는데 실패합니다. 명령이 전혀 실행되지 않습니다.


정말 고마워. 매뉴얼 페이지에 "... 출력을 재 지정할 수 없으면 프로그램이 실행되지 않을 것"으로 약간 설명하기를 바랍니다.
Charlie Dalsass

업데이트; 아래의 일부 단락이 숨겨져 있습니다.
Murphy

실제로, 그것은 분명하다. "파일을 열거 나 만들지 못하면 리디렉션이 실패합니다." 거기는. 다시 감사합니다.
Charlie Dalsass

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()exec(): 그것은 전에 일어날 수 fork()는 쉘의 표준 출력을 변경하지해야하기 때문에, 그것은 이후에 발생할 수 없습니다 exec()파일 이름과 쉘의 실행 코드는 이제 파이썬 프로그램으로 대체 되었기 때문에 . 부모는 자식의 파일 설명자에 액세스 할 수 없습니다 (그렇더라도 exec()stdout으로의 첫 번째 쓰기와 리디렉션 사이를 리디렉션 할 수는 없습니다 ).


0

그것이 정반대라는 것을 알려 드리게되어 유감입니다. 쉘은 I / O를 먼저 연 다음 제어를 프로그램에 전달해야합니다.

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


티가 실패한 후에 파이썬 스크립트가 SIGPIPE에서 죽지 않습니까?
Kevin

내가 한 테스트에 따르면 아니지만 시도해 볼 것을 제안합니다.
Julie Pelletier
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.