Program Bash nie zostanie wykonany, jeśli przekierowanie nie powiedzie się


9

W bash zauważam, że jeśli polecenie korzystające z przekierowania nie powiedzie się, wszystkie programy, które działają wcześniej, nie zostaną uruchomione.

Na przykład ten program otwiera plik „a” i zapisuje 50 bajtów w pliku „a”. Jednak uruchomienie tego polecenia z przekierowaniem do pliku o niewystarczających uprawnieniach (~ root / log) nie powoduje zmiany rozmiaru pliku „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

Można by pomyśleć, że program uruchomi się, przechwyci dowolne dane wyjściowe (ale także zapisze do pliku „a”), a następnie nie zapisuje żadnych danych wyjściowych do ~ root / log. Zamiast tego program nigdy nie jest uruchamiany.

Dlaczego tak jest i w jaki sposób bash wybiera kolejność „kontroli”, które wykonuje przed uruchomieniem programu? Czy przeprowadzane są również inne kontrole?

ps Próbuję ustalić, czy program działający pod cronem faktycznie działał po przekierowaniu do pliku „odmowy uprawnień”.


Wszystko jest w dobrym stanie technicznym (tj. Własność i uprawnienia do pliku .py, to znaczy), twój program działa dobrze. Twoje problemy pochodzą z przekierowania. Nie masz uprawnień do napisania katalogu filein / root. I przekierowałeś swoje, stdoutaby zrobić dokładnie to. Tak więc nie zobaczysz żadnych danych wyjściowych, nawet jeśli Twój program został uruchomiony.
MelBurslan

2
Mel, to nieprawda, program nigdy się nie uruchomił. Zobacz odpowiedzi poniżej.
Charlie Dalsass

Ty: „Uruchom write_file.pyprogram i wyślij jego wynik do ~root/logbash:„ Przepraszam, ale nie możesz pisać do tego pliku! ”Powłoka robi dokładnie to, co powinna. Jeśli nie może zrobić tego, o co prosiłeś zrób to, natychmiast poinformuje cię, dlaczego jest problem, dając ci możliwość podjęcia decyzji, jak sobie z tym poradzić. Dla wszystkich opiekunów bash wie, bardzo złe rzeczy mogą się zdarzyć, jeśli uruchomisz to polecenie i nie będziesz mógł zapisać danych wyjściowych. Gdyby było wystarczająco ważne, abyś wyznaczył miejsce, aby go zapisać, byłoby źle, gdyby ASS | U | ME działało bez zapisywania standardowego wyjścia.
Monty Harder

Odpowiedzi:


18

Tak naprawdę nie jest to kwestia zamawiania czeków, po prostu kolejność, w jakiej powłoka konfiguruje rzeczy. Przekierowania są konfigurowane przed uruchomieniem polecenia; więc w twoim przykładzie powłoka próbuje otworzyć się ~root/logprzed dołączeniem przed próbą wykonania czegokolwiek, co wymaga ./write_file.py. Ponieważ nie można otworzyć pliku dziennika, przekierowanie kończy się niepowodzeniem, a powłoka przestaje w tym momencie przetwarzać wiersz poleceń.

Jednym ze sposobów wykazania tego jest pobranie pliku niewykonywalnego i próba jego uruchomienia:

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

To pokazuje, że powłoka nawet nie patrzy, ./demokiedy nie można skonfigurować przekierowania.


Wow, to takie proste? Nie zdawałem sobie sprawy, że przekierowania zostały wykonane jako pierwsze. Dzięki za tę odpowiedź, a także za inne świetne odpowiedzi.
Charlie Dalsass

6
Jeśli nie zostałyby zrobione najpierw, gdzie zapisano by dane wyjściowe?
Charles Duffy

A jeśli nie można zapisać danych wyjściowych, skąd wiemy, że uruchomienie polecenia jest bezpieczne? Być może polecenie wyświetla informacje usuwane ze składnicy danych i absolutnie konieczne jest przechwycenie danych wyjściowych. Dobrze, że bash nie pozwoli, aby działał, dopóki nie naprawisz tych uprawnień, co?
Monty Harder

11

Ze strony podręcznika użytkownika bash, sekcja REDIRECTION (podkreślenie przeze mnie):

Przed wykonaniem polecenia jego dane wejściowe i wyjściowe mogą zostać przekierowane przy użyciu specjalnej notacji interpretowanej przez powłokę.

...

Niepowodzenie otwarcia lub utworzenia pliku powoduje niepowodzenie przekierowania.

Więc powłoka próbuje otworzyć plik docelowy stdout, co się nie powiedzie, a polecenie w ogóle nie zostanie wykonane.


Dzięki wielkie. Chciałbym, aby strona podręcznika wyjaśniła nieco „... jeśli wyjście nie może zostać przekierowane, program nie zostanie wykonany”.
Charlie Dalsass

Zaktualizowano; jest raczej ukryty w kilku akapitach poniżej.
Murphy

Właściwie to całkiem jasne. „Niepowodzenie otwarcia lub utworzenia pliku powoduje niepowodzenie przekierowania.” Tu jest. Dzięki jeszcze raz.
Charlie Dalsass 27.04.16

3

Warto zauważyć, że powłoka musi ustanowić przekierowania przed uruchomieniem programu.

Rozważ swój przykład:

./write_file.py >> ~root/log

To, co dzieje się w powłoce, to:

  1. My (powłoka) fork(); proces potomny dziedziczy otwarte deskryptory plików od swojego rodzica (powłoki).
  2. W procesie potomnym my fopen()(rozwinięcie) „~ root / log” i dup2()to do fd 1 (i close()tymczasowego fd). Jeśli się fopen()nie powiedzie, zadzwoń, exit()aby zgłosić błąd rodzicowi.
  3. Wciąż w dziecku mamy exec()„./write_file.py”. W tym procesie nie działa już żaden z naszych kodów (chyba że nie udało się go wykonać, w którym to przypadku exit()zgłosimy błąd do rodzica).
  4. Element nadrzędny sprawi, wait()że dziecko zakończy działanie i obsłuży swój kod wyjścia (kopiując go $?przynajmniej do).

Przekierowanie musi więc nastąpić w podrzędnym między fork()i exec(): nie może się zdarzyć wcześniej, fork()ponieważ nie może zmienić standardowej powłoki powłoki, i nie może nastąpić później, exec()ponieważ nazwa pliku i kod wykonywalny powłoki zostały teraz zastąpione przez program Python . Rodzic nie ma dostępu do deskryptorów plików dziecka (a nawet gdyby tak było, nie mógł zagwarantować przekierowania między exec()pierwszym zapisem na standardowe wyjście).


0

Z przykrością informuję, że jest odwrotnie. Powłoka musi najpierw otworzyć swoje we / wy, a następnie przekazać kontrolę programowi.

tee może okazać się pomocny w tym przypadku: ./write_file.py | tee -a ~root/log > /dev/null


Czy skrypt Pythona nie umiera po SIGPIPE po awarii tee?
Kevin

Nie według testu, który zrobiłem, ale sugeruję, abyś spróbował.
Julie Pelletier
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.