Dlaczego niektóre polecenia „zawieszają” terminal, dopóki nie skończą?

22

Czasami uruchamiasz program z terminala, powiedzmy lxpanel . Terminal nie odeśle cię z powrotem do monitu, zawiesi się. Możesz nacisnąć Ctrl+, Caby wrócić do monitu, ale to zabije lxpanel. Jednak naciśnięcie Alt+ F2(które wyskakuje okno, aby wykonać polecenie) i uruchomienie lxpaneldziała z wdziękiem.

Dlaczego to? Czym różni się uruchamianie polecenia z terminala i od okna „uruchom”, które pojawia się po naciśnięciu Alt+ F2?

lxpanel został tutaj użyty jako przykład. Doświadczyłem tego z wieloma programami

sqram
źródło
1
Wskazówka: GNU Screen ( screen) może między innymi służyć do „zawijania” dłuższych procesów. Możesz się od niego odłączyć, wracając do powłoki, a następnie ponownie podłączyć i zobaczyć dane wyjściowe z uruchomionego procesu. Ponowne podłączenie można wykonać nawet z innego terminala, SSH itp. Mogą też istnieć inne programy, które pozwalają ci robić takie rzeczy.
poplitea

Odpowiedzi:

28

Domyślnie terminal uruchomi program na pierwszym planie, więc nie skończysz w powłoce, dopóki program się nie zakończy. Jest to przydatne dla programów, które czytają ze standardowego wejścia i / lub zapisują na standardowe wyjście - generalnie nie chcesz, aby wiele z nich działało jednocześnie. Jeśli chcesz, aby program działał w tle, możesz uruchomić go w następujący sposób:

$ lxpanel &

Lub jeśli już działa, możesz go zawiesić za pomocą Ctrl+, Za następnie uruchomić, bgaby przenieść go w tło. Tak czy inaczej skończy się nowy monit powłoki, ale program nadal działa, a jego dane wyjściowe pojawią się w terminalu (więc może nagle pojawić się, gdy jesteś w trakcie pisania)

Niektóre programy (zwykle demony) rozwidlają osobny proces podczas uruchamiania, a następnie pozwalają procesowi głównemu natychmiast wyjść. Dzięki temu program będzie działał bez blokowania powłoki

Michał Mrożek
źródło
Co właściwie robi system, gdy uruchamiasz program za pomocą okna „uruchom”, naciskając klawisze Alt + f2? (przynajmniej na gnome i openbox, robi to alt + f2). Pytam, bo jak tylko wpiszesz polecenie, program się uruchomi, a okno zniknie. czy to tylko dodanie do niego znaku &?
sqram
2
@lyrae: domyślnie powłoka czeka na zakończenie działania programu przed kontynuowaniem sesji powłoki, nie „zawiesza się”, przy żadnej definicji „zawiesić”; Alt + F2 nie czeka na program. Powodem, dla którego powłoka czeka na zakończenie programu, jest to, że powłoka może przekierowywać wszystko, co użytkownik wpisał do powłoki, na standardowe wejście programu i / lub wyświetlać standardowe wyjście programu. Ponieważ alt + f2 jest używany przede wszystkim do uruchamiania programu GUI, alt + f2 nie zapewnia możliwości użycia standardowego wejścia / wyjścia, więc nie trzeba czekać.
Lie Ryan,
1
@lyrae: alt + f2 nie robi nic specjalnego, aby uruchomić program w tle; to powłoka robi coś specjalnego, dodanie „&” to funkcjonalność powłoki. Podczas uruchamiania polecenia bez znaku „&” powłoka przekierowuje standardowe wejście programu na własne standardowe wejście, a standardowe wyjście programu na własne standardowe wyjście (nieco wymyślone, ponieważ powłoka udostępnia również wiele innych usług, takich jak przechwytywanie Ctrl -C, aby wysłać polecenie sygnału SIGINT do programu pierwszego planu). „&” Mówi powłoce, aby tego nie robiła i po prostu uruchamia program (również zaprojektowany).
Lie Ryan,
1
@LieRyan część tego, co mówisz, że robi powłoka, jest w rzeczywistości obsługiwana przez sterownik terminalu jądra, a „with &” jest ogólnie bardziej „specjalne” niż „bez &”, poza tym, że powłoka wywołuje funkcję wait () [lub waitpid lub równoważny], którego nie robi alt-f2.
Random832
6

Po uruchomieniu programu w terminalu terminal „zawiesi się”, dopóki program się nie zatrzyma. Naciskając Ctrl+ czamykasz program, a tym samym wracasz do monitu. Zobaczysz to we wszystkich aplikacjach GUI, na przykład wypróbuj Firefox.

Kiedy użyjesz innej metody, takiej jak Alt + F2 lub klikniesz menu, twój program zostanie uruchomiony w tle, więc nic dziwnego się nie wydarzy (i tak czy inaczej nie ma wiersza polecenia).

Jeśli nadal chcesz uruchamiać aplikacje GUI z terminala, dołącz &na końcu polecenia, tak jak to

lxpanel &

Mówi to terminalowi, aby działał lxpanelw tle i natychmiast wyświetla kolejny monit.

phunehehe
źródło
3

Programy domyślnie uruchamiane są przez powłokę na pierwszym planie tej powłoki. Powoduje to, że powłoka zawiesza działanie i kieruje stdin / stdout / sterr z terminala do programu. Programy uruchamiane za pomocą środowiska pulpitu są rozwidlone , co powoduje, że działają niezależnie od programu, który je uruchomił. Można to zasymulować w większości powłok, dodając a &do polecenia, chociaż to wciąż połączy std * z terminalem (chociaż czytanie ze stdin w programie w tle ma dalsze komplikacje).

Ignacio Vazquez-Abrams
źródło
2

Tła i dobrze, z wyjątkiem programów, które powracają w późniejszym czasie wymagających interakcji z konsolą (na przykład „apt -y update &”, który ostatecznie przechodzi w stan STOP, ponieważ chce poprosić użytkownika o pytanie „naprawdę naprawdę wymuszać?” Znacznie później .... kiedy nikt już nie patrzy).

Aby podłączyć tę dziurę i poinformować proces, że terminal nigdy tak naprawdę nigdy nie będzie dla niego dostępny, dołączam <& - do niektórych moich poleceń, całkowicie odłączając je od aktywnego terminala informując, że STDIN nie jest już możliwe. Upewnij się jednak, że / bin / bash jest twoją powłoką, jeśli z niej korzystasz. Skrypt będzie rejestrował wszelkie błędy związane z brakiem dostępu do pseudoterminalu, na którym można by rzucić dowolny monit.

Na przykład:

`./runme.sh &> runme.log <&- & disown`

to mój najlepszy sposób na odłączenie się od bieżącej sesji terminala. Zarówno STDOUT, jak i STDERR zostają zalogowane do runme.log, nie będzie miało znaczenia, czy konsola lub powłoka zakończą się wcześniej, czy wylogujesz się / su na inne konto (bez śmieci terminali z runme), a dzięki odrzuceniu nawet rodzic-dziecko Relacja PID została usunięta.

AKTUALIZACJA: nawet z tym miałem problem z semaforem powiązanym z nazwą oryginalnego rodzica, więc teraz polecam zamiast tego:

at now <<< "(cmd1; cmd2; etc.) &> logfile.log"

Oczywiście, usuń &>, jeśli chcesz otrzymać dane wyjściowe z CRON w e-mailu lub przekieruj wszystko do / dev / null zamiast pliku.

Marcos
źródło
Nieco mniej skomplikowanym sposobem na osiągnięcie tego, z którego zacząłem korzystać, jestat now <<< "(cmd1; cmd2; etc.) &> logfile.log"
Marcos