Jak uruchomić polecenie, które przetrwa zamknięcie terminala?


313

Czasami chcę rozpocząć proces i zapomnieć o nim. Jeśli uruchomię go z wiersza poleceń, tak:

redshift

Nie mogę zamknąć terminalu, bo to zabije proces. Czy mogę uruchomić polecenie w taki sposób, że mogę zamknąć terminal bez zabijania procesu?


4
Nie jest to domyślna instalacja na wszystkich dystrybucjach, ale screen jest twoim przyjacielem: en.wikipedia.org/wiki/GNU_Screen
Zayne S Halsall

Dla każdego, kto boryka się z tym samym problemem: pamiętaj, że nawet jeśli piszesz, yourExecutable &a wyniki wciąż pojawiają się na ekranie i Ctrl+Cnie wydają się niczego zatrzymywać, po prostu ślepo wpisz disown;i naciśnij, Enternawet jeśli ekran przewija się z wyjściami i nie możesz zobaczyć, co piszesz. Proces zostanie odrzucony, a ty będziesz mógł zamknąć terminal bez śmierci procesu.
Nav

Możesz użyć multipleksera ekranowego, takiego jak Tmux . Jest on dostępny za pośrednictwem apt-get na maszynach Ubuntu
Himanshu

Odpowiedzi:


311

Jedna z następujących 2 powinna działać:

$ nohup redshift &

lub

$ redshift &
$ disown

Zobacz poniższe, aby uzyskać więcej informacji na temat tego, jak to działa:


5
Drugi ( redshift & disown) pracował dla mnie na Ubuntu 10.10. Wygląda na to, że działa dobrze, umieszczając wszystko w jednym wierszu. Czy jest jakiś powód, dla którego nie powinienem tego robić?
Matthew

4
@Matthew Pierwszy powinien również działać dobrze, po prostu nie ma tła jak drugi (być może chcesz, nohup redshift &więc działa w tle). A umieszczenie drugiego w jednym wierszu jest w porządku, chociaż zwykle oddzielamy się od ;( redshift &; disown)
Michael Mrozek

10
@Michael: Obie ;i &są separatorami komend i mają równe pierwszeństwo. Jedyną różnicą jest odpowiednio synchroniczne i asynchroniczne wykonanie. Nie ma potrzeby używania &;zamiast preferencji &(działa, ale jest nieco redundantne).
Chris Johnsen,

4
dobra odpowiedź, można dodać, że dobrym pomysłem byłoby przekierowanie stdout i stderr, aby terminal nie był spamowany wyjściem debugowania
Kim

12
Ponadto redshift &!natychmiast odrzuci przesunięcie ku czerwieni.

143

Jeśli twój program już działa , możesz go zatrzymać Ctrl-Z, pociągnąć w tło za pomocą, bga następnie w disownnastępujący sposób:

$ sleep 1000
^Z
[1]+  Stopped                 sleep 1000
$ bg
$ disown
$ exit

3
po odrzuceniu, w jaki sposób mogę ponownie odczytać standardowe etapy uruchomionego procesu?
Necktwi


1
Z jakiegoś powodu to nie zadziałało (centos)
Ian

Jak zabić proces po tej procedurze?
Palak Darji

2
@necktwi disownnie odłącza stdout ani stderr. Jednak nohuppodobnie jak >/dev/null(odłącz standardowe wyjście), 2>/dev/null(odłącz standardowy błąd). To ( disown) rozłącza kontrolę zadań.
ctrl-alt-delor

45

Dobra odpowiedź jest już opublikowana przez @StevenD, ale myślę, że może to nieco to wyjaśnić.

Powodem, dla którego proces zostaje zabity po zakończeniu terminala, jest to, że proces, który uruchamiasz, jest procesem potomnym terminala. Gdy zamkniesz terminal, zabije to również te procesy potomne. Możesz zobaczyć drzewo procesów pstree, na przykład podczas uruchamiania kate &w Konsoli:

init-+
     ├─konsole─┬─bash─┬─kate───2*[{kate}]
     │         │      └─pstree
     │         └─2*[{konsole}]

Aby kateproces został odłączony konsolepo zakończeniu konsole, użyj nohuppolecenia:

nohup kate &

Po zamknięciu konsole, pstreebędzie wyglądać następująco:

init-+
     |-kate---2*[{kate}]

i kateprzetrwa. :)

Alternatywą jest użycie screen/ tmux/ byobu, które utrzyma działanie powłoki, niezależnie od terminala.


Miałem problemy z odrzuconymi metodami. To działa obecnie dla mnie, więc upvoting. Lubię to również, ponieważ mogę ogonić -h nohup.out, aby zobaczyć, co się dzieje, ale nie martw się, że moja sesja się nie powiedzie
Ian

27

Możesz uruchomić taki proces w terminalu

setsid process

Spowoduje to uruchomienie programu w nowej sesji. Jak wyjaśniono http://hanoo.org/index.php?article=run-program-in-new-session-linux


1
Co widzisz jako zalety setid nad nohup?
itsbruce

1
1) Nie drukuje irytującej wiadomości nohup.out. 2) Nie pozostaje na liście zadań twojej powłoki, więc nie zaśmieca wyników jobs.
Mikel

Jest to jedyne rozwiązanie, które działało ze skryptem działającym w lxterminal, uruchamia pcmanfm i kończy działanie (z setsid terminal może się zamknąć, podczas gdy pcmanfm nadal działa). Dziękuję bardzo!
desgua

9

Chociaż wszystkie sugestie działają dobrze, znalazłem moją alternatywą jest użycie screenprogramu, który konfiguruje wirtualny terminal na ekranie.

Możesz rozważyć rozpoczęcie od . Screen może być zainstalowany na praktycznie wszystkich pochodnych Linux i Unix. Naciśnięcie + i (małe litery) rozpocznie drugą sesję. Umożliwiłoby to przełączanie się między początkową sesją, naciskając + i / lub nowszą sesją, naciskając + i . W jednym terminalu możesz mieć do dziesięciu sesji. Kiedyś zaczynałem sesję w pracy, wracałem do domu, ssh na mojej maszynie roboczej, a potem wywoływałem . Spowoduje to ponowne połączenie się z tą zdalną sesją.screen -S session_nameCtrlACCtrlA0CtrlA1screen -d -R session_name


screen -d -m commandrozpocznie się na już odłączonym ekranie: ~# screen -d -m top ~# screen -ls There is a screen on: 10803..Server-station (Detached) 1 Socket in /root/.screen. ~# screen -x .... i jesteś w środku.
Dr Alexander

7

Jedynym sposobem na wykonanie tego wszystkiego jest zamknięcie stdin i umieszczenie w tle polecenia:

command <&- & 

Wtedy nie wyjdzie, gdy opuścisz powłokę. Przekierowanie standardowego wyjścia jest fajną opcjonalną rzeczą do zrobienia.

Wadą jest to, że nie można tego zrobić po fakcie.


Próbowałem w ubuntu. Terminal zabijania również zamknął uruchomiony proces. Masz pomysł, dlaczego tak może być?
Ashok Koyi

7

Mam skrypt do:

  • Uruchom dowolne polecenia w tle

  • Powstrzymaj ich przed zabiciem za pomocą okna terminala

  • Pomiń ich wydajność

  • Obsługuje status wyjścia

Używam go głównie do gedit, evince, inkscapeetc, że wszyscy mają mnóstwo irytujących wyjścia terminala. Jeśli polecenie zakończy się wcześniej TIMEOUT, status wyjścia nohup jest zwracany zamiast zera.

#!/bin/bash

TIMEOUT=0.1

#use nohup to run the command, suppressing its output and allowing the terminal to be closed
#also send nohup's output to /dev/null, supressing nohup.out
#run nohup in the background so this script doesn't block
nohup "${@}" >/dev/null 2>&1 &
NOHUP_PID=$!

#kill this script after a short time, exiting with success status - command is still running
#this is needed as there is no timeout argument for `wait` below
MY_PID=$$
trap "exit 0" SIGINT SIGTERM
sleep $TIMEOUT && kill $MY_PID 2>/dev/null & #ignore "No such process" error if this exits normally

#if the command finishes before the above timeout, everything may be just fine or there could have been an error
wait $NOHUP_PID
NOHUP_STATUS=$?
#print an error if there was any. most commonly, there was a typo in the command
[ $NOHUP_STATUS != 0 ] && echo "Error ${@}"
#return the exit status of nohup, whatever it was
exit $NOHUP_STATUS

przykłady ...

>>> run true && echo success || echo fail
success
>>> run false && echo success || echo fail
Error false
fail
>>> run sleep 1000 && echo success || echo fail
success
>>> run notfound && echo success || echo fail
Error notfound
fail

6

Wolę:

(Nazwa aplikacji &)

na przykład: linux@linux-desktop:~$ (chromium-browser &)

Pamiętaj, aby użyć nawiasu podczas wpisywania polecenia!


1
Zamknięcie terminalu zabije proces , którego dokładnie chce OP (i ja, a więc przybywając tutaj)
gromit190,

Prawdopodobnie masz szybką komendę, której użyłem w mojej odpowiedzi bez nawiasów, jeśli tak zamknięcie terminalu zabije proces, w przeciwnym razie NIE nastąpi. Zredagowałem już powyższe rozwiązanie, aby było jasne.
daGo

pracuj dla mnie,
tnx

Zastanawiam się, dlaczego nie zyskało to więcej pochwał. nohupzapobiega wszelkim wynikom tty, a ja po prostu chciałem przekierować dane wyjściowe do pliku i zapobiegło to, więc jest to dla mnie lepsze rozwiązanie.
redanimalwar

4

Możesz ustawić proces (PID), aby nie odbierał sygnału HUP po wylogowaniu i zamknięciu sesji terminala. Użyj następującego polecenia:

nohup -p PID

3

Prawdopodobnie podobny do odpowiedzi oferowanej przez apolinsky , używam wariantu na screen. Polecenie waniliowe jest takie

screen bash -c 'long_running_command_here; echo; read -p "ALL DONE:"'

Sesję można rozłączyć Ctrl ACtrl Di ponownie połączyć w prostym przypadku z screen -r. Mam to zawinięte w skrypt o nazwie, sessionktóry żyje w mojej PATHgotowości do wygodnego dostępu:

#!/bin/bash
#
if screen -ls | awk '$1 ~ /^[1-9][0-9]*\.'"$1"'/' >/dev/null
then
    echo "WARNING: session is already running (reattach with 'screen -r $1')" >&2
else
    exec screen -S "$1" bash -c "$@; echo; echo '--------------------'; read -p 'ALL DONE (Enter to exit):'"
    echo "ERROR: 'screen' is not installed on this system" >&2
fi
exit 1

Działa to tylko wtedy, gdy wiesz z góry, że chcesz odłączyć program. Nie zapewnia odłączenia już działającego programu.


2

Podobnie jak w przypadku innych odpowiedzi opublikowanych wcześniej, można przenieść działający proces, aby użyć retrospektywnie „ekranu” dzięki reptyr, a następnie zamknąć terminal. Kroki opisano w tym poście . Kroki, które należy podjąć, to:

  1. Zawieś proces
  2. Wznów proces w tle
  3. Odrzuć proces
  4. Uruchom sesję ekranową
  5. Znajdź PID procesu
  6. Użyj reptyr, aby przejąć proces
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.