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ń”.
źródło
stdout
aby zrobić dokładnie to. Tak więc nie zobaczysz żadnych danych wyjściowych, nawet jeśli Twój program został uruchomiony.write_file.py
program i wyślij jego wynik do~root/log
bash:„ 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.Odpowiedzi:
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/log
przed 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:
To pokazuje, że powłoka nawet nie patrzy,
./demo
kiedy nie można skonfigurować przekierowania.źródło
Ze strony podręcznika użytkownika bash, sekcja REDIRECTION (podkreślenie przeze mnie):
Więc powłoka próbuje otworzyć plik docelowy
stdout
, co się nie powiedzie, a polecenie w ogóle nie zostanie wykonane.źródło
Warto zauważyć, że powłoka musi ustanowić przekierowania przed uruchomieniem programu.
Rozważ swój przykład:
To, co dzieje się w powłoce, to:
fork()
; proces potomny dziedziczy otwarte deskryptory plików od swojego rodzica (powłoki).fopen()
(rozwinięcie) „~ root / log” idup2()
to do fd 1 (iclose()
tymczasowego fd). Jeśli sięfopen()
nie powiedzie, zadzwoń,exit()
aby zgłosić błąd rodzicowi.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 przypadkuexit()
zgłosimy błąd do rodzica).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()
iexec()
: 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ędzyexec()
pierwszym zapisem na standardowe wyjście).źródło
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
źródło