Jak ustawić działający już proces pod nohup?

940

Mam proces, który działa już od dłuższego czasu i nie chcę go kończyć.

Jak ustawić go w tryb nohup (to znaczy, jak sprawić, aby nadal działał, nawet jeśli zamknę terminal?)

Lecieć jak po sznurku
źródło
29
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

Odpowiedzi:

1367

Korzystanie z kontroli zadań bash, aby wysłać proces w tle:

  1. Ctrl+, Zaby zatrzymać (wstrzymać) program i wrócić do powłoki.
  2. bg aby uruchomić go w tle.
  3. disown -h [job-spec]gdzie [specyfikacja zadania] to numer zadania (jak %1dla pierwszego uruchomionego zadania; znajdź swój numer za pomocą jobspolecenia), aby zadanie nie zostało zabite, gdy terminal zostanie zamknięty.
Węzeł
źródło
38
Ponieważ pytanie brzmiało, jak „umieścić to pod nohup”, disown -hbyć może jest bardziej dokładna odpowiedź: „spraw, aby disown zachowywał się bardziej jak nohup (tzn. Zadania pozostaną w drzewie procesów bieżącej powłoki, dopóki nie opuścisz powłoki) To pozwala ci zobaczyć wszystkie zadania uruchomione przez tę powłokę. ” (z [ quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/… )
Dr Jan-Philip Gehrcke
8
Jak mogę później odzyskać pracę? Widzę, że działa przy użyciu ps -e.
Paulo Casaretto,
26
Nie widać wyniku zadania po disown, disown czyni proces demonem, co oznacza, że ​​standardowe wejścia / wyjścia są przekierowywane do / dev / null. Jeśli więc planujesz odrzucić zadanie, lepiej zacząć od zalogowania się do pliku, np.my_job_command | tee my_job.log
rustyx
8
czy można w jakiś sposób zrobić coś takiego jak „my_job_command | tee my_job.log ' po uruchomieniu polecenia?
arod
23
disownoddziela wszelkie rury od procesu. Aby ponownie przymocować rury, użyj gdbzgodnie z opisem w tym wątku . Mówiąc dokładniej, ten post .
mbrownnyc
185

Załóżmy, że z jakiegoś powodu Ctrl+ Zrównież nie działa, przejdź do innego terminala, znajdź identyfikator procesu (za pomocą ps) i uruchom:

kill -SIGSTOP PID 
kill -SIGCONT PID

SIGSTOPzawiesi proces i SIGCONTwznowi proces w tle. Więc teraz zamknięcie obu terminali nie zatrzyma twojego procesu.

Płuca
źródło
10
Tak, to problem z systemem operacyjnym, kill nie działa z Cygwin w systemie Windows.
Pungs 11.11.13
6
Jest to również bardzo przydatne, jeśli zadanie jest uruchamiane z innej sesji ssh.
Amir Ali Akbari
5
Pamiętaj tylko, aby zrobić to disown %1w pierwszym terminalu przed jego zamknięciem.
fred
1
Jest to przydatne, ponieważ uruchomiłem interfejs graficzny z konsolą (w moim przypadku zacząłem od konsoli kwinpo awarii bez myślenia o konsekwencjach). Więc gdybym przestał kwin, wszystko by się zawiesiło i nie miałem możliwości biegać bg!
Michele,
@fred Nie zrobiłem tego i wydawało się, że nadal działa. Możliwe czy trafiłem w zły PID?
Nikt
91

Polecenie oddzielenia uruchomionego zadania od powłoki (= powoduje, że nie jest to żadna czynność) jest disownpodstawowym poleceniem powłoki.

Z bash-manpage (man bash):

disown [-ar] [-h] [jobspec ...]

Bez opcji każdy rodzaj zadania jest usuwany z tabeli aktywnych zadań. Jeśli podano opcję -h, każdy parametr zadania nie jest usuwany z tabeli, ale jest oznaczony tak, że SIGHUP nie jest wysyłany do zadania, jeśli powłoka otrzyma SIGHUP. Jeśli nie podano specyfikacji zadania i nie podano opcji -a ani -r, używane jest bieżące zadanie. Jeśli nie podano specyfikacji zadania, opcja -a oznacza usunięcie lub zaznaczenie wszystkich zadań; opcja -r bez argumentu spec zadania ogranicza operację do uruchamiania zadań. Zwracana wartość wynosi 0, chyba że specyfikacja zadania nie określa poprawnego zadania.

To znaczy, że to proste

disown -a

usunie wszystkie zadania z tabeli zadań i sprawi, że nie będą działać

serioys sam
źródło
9
disown -ausuwa wszystkie zadania. Prosty disownusuwa tylko bieżące zadanie. Jak mówi strona podręcznika w odpowiedzi.
Rune Schjellerup Philos z
73

Oto dobre odpowiedzi powyżej, chciałem tylko dodać wyjaśnienie:

Nie możesz disownpłacić ani przetwarzać, jesteś disownpracą, a to ważne rozróżnienie.

Zadanie jest czymś, co jest pojęciem związanym z powłoką, dlatego musisz rzucić zadanie w tło (nie zawieszać go), a następnie odrzucić.

Kwestia:

%  jobs
[1]  running java 
[2]  suspended vi
%  disown %1

Zobacz http://www.quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/jobcontrol/, aby uzyskać bardziej szczegółowe omówienie Unix Job Control.

Q Kocioł
źródło
48

Niestety disownjest specyficzny dla bash i nie jest dostępny we wszystkich powłokach.

Niektóre warianty Uniksa (np. AIX i Solaris) mają opcję w nohupsamej komendzie, którą można zastosować do uruchomionego procesu:

nohup -p pid

Zobacz http://en.wikipedia.org/wiki/Nohup

Dołek
źródło
Tylko dla AIXi Solaris. „Wersje nohup w systemach AIX i Solaris mają opcję -p, która modyfikuje uruchomiony proces w celu zignorowania przyszłych sygnałów SIGHUP. W przeciwieństwie do opisanego powyżej wbudowanego bash, nohup -p akceptuje identyfikatory procesów.”. Źródło
AlikElzin-kilaka
27

Odpowiedź węzła jest naprawdę świetna, ale pozostawiło otwarte pytanie, w jaki sposób można przekierować stdout i stderr. Znalazłem rozwiązanie w systemach Unix i Linux , ale nie jest ono również kompletne. Chciałbym połączyć te dwa rozwiązania. Oto on:

Dla mojego testu stworzyłem mały skrypt bash o nazwie loop.sh, który drukuje swój pid z chwilą snu w nieskończonej pętli.

$./loop.sh

Teraz jakoś uzyskaj PID tego procesu. Zwykle ps -C loop.shjest wystarczająco dobry, ale jest wydrukowany w moim przypadku.

Teraz możemy przełączyć się na inny terminal (lub nacisnąć ^ Z i w tym samym terminalu). Teraz gdbnależy dołączyć do tego procesu.

$ gdb -p <PID>

To zatrzymuje skrypt (jeśli jest uruchomiony). Jego stan można sprawdzić ps -f <PID>, gdzie STATpole to „T +” (lub w przypadku ^ Z „T”), co oznacza (man ps (1))

    T Stopped, either by a job control signal or because it is being traced
    + is in the foreground process group

(gdb) call close(1)
$1 = 0

Close (1) zwraca zero po sukcesie.

(gdb) call open("loop.out", 01102, 0600)
$6 = 1

Open (1) zwraca nowy deskryptor pliku, jeśli się powiedzie.

To otwarcie jest równe open(path, O_TRUNC|O_CREAT|O_RDWR, S_IRUSR|S_IWUSR). Zamiast O_RDWR O_WRONLYmożna zastosować, ale /usr/sbin/lsofmówi „u” dla wszystkich procedur obsługi plików std * ( FDkolumna), co oznacza O_RDWR.

Sprawdziłem wartości w pliku nagłówkowym /usr/include/bits/fcntl.h.

Plik wyjściowy można otworzyć za pomocą O_APPEND, podobnie jak w nohupprzypadku, ale nie jest to sugerowane przez man open(2), ze względu na możliwe problemy z NFS.

Jeśli otrzymamy -1 jako wartość zwracaną, to call perror("")drukuje komunikat o błędzie. Jeśli potrzebujemy errno, użyj polecenia p errnogdb.

Teraz możemy sprawdzić nowo przekierowany plik. /usr/sbin/lsof -p <PID>drukuje:

loop.sh <PID> truey    1u   REG   0,26        0 15008411 /home/truey/loop.out

Jeśli chcemy, możemy przekierować stderr do innego pliku, jeśli chcemy użyć call close(2)i call open(...)ponownie używając innej nazwy pliku.

Teraz załączony bashmusi zostać zwolniony i możemy wyjść gdb:

(gdb) detach
Detaching from program: /bin/bash, process <PID>
(gdb) q

Jeśli skrypt został zatrzymany przez gdbinny terminal, kontynuuje działanie. Możemy wrócić do terminalu loop.sh. Teraz nic nie zapisuje na ekranie, ale działa i zapisuje do pliku. Musimy to umieścić w tle. Więc naciśnij ^Z.

^Z
[1]+  Stopped                 ./loop.sh

(Teraz jesteśmy w takim samym stanie, jak ^Zna początku naciśnięto).

Teraz możemy sprawdzić stan zadania:

$ ps -f 24522
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID><PPID>  0 11:16 pts/36   S      0:00 /bin/bash ./loop.sh
$ jobs
[1]+  Stopped                 ./loop.sh

Tak więc proces powinien być uruchomiony w tle i odłączony od terminala. Liczba w jobswynikach polecenia w nawiasach kwadratowych oznacza zadanie wewnątrz bash. Możemy użyć następujących wbudowanych bashpoleceń, stosując znak „%” przed numerem zadania:

$ bg %1
[1]+ ./loop.sh &
$ disown -h %1
$ ps -f <PID>
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID><PPID>  0 11:16 pts/36   S      0:00 /bin/bash ./loop.sh

A teraz możemy wyjść z bashu wywołującego. Proces jest kontynuowany w tle. Jeśli wyjdziemy, jego PPID zmieni się na 1 (proces init (1)), a terminal kontrolny stanie się nieznany.

$ ps -f <PID>
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID>     1  0 11:16 ?        S      0:00 /bin/bash ./loop.sh
$ /usr/bin/lsof -p <PID>
...
loop.sh <PID> truey    0u   CHR 136,36                38 /dev/pts/36 (deleted)
loop.sh <PID> truey    1u   REG   0,26     1127 15008411 /home/truey/loop.out
loop.sh <PID> truey    2u   CHR 136,36                38 /dev/pts/36 (deleted)

KOMENTARZ

Pliki gdb można zautomatyzować, tworząc plik (np. Loop.gdb) zawierający polecenia i uruchamiany gdb -q -x loop.gdb -p <PID>. Mój loop.gdb wygląda następująco:

call close(1)
call open("loop.out", 01102, 0600)
# call close(2)
# call open("loop.err", 01102, 0600)
detach
quit

Lub zamiast tego można użyć jednej wkładki:

gdb -q -ex 'call close(1)' -ex 'call open("loop.out", 01102, 0600)' -ex detach -ex quit -p <PID>

Mam nadzieję, że jest to dość kompletny opis rozwiązania.

Prawda
źródło
Rzeczywiście bardzo pouczające i może działać dobrze w prostych przypadkach. Ale uwaga, bardziej złożone przypadki mogą zawieść nieszczęśliwie. Miałem jeden z nich dzisiaj: mój proces zrodził inny proces, który wykonał wynik (przypuszczalnie do stderr), ale stdout podłączył się do komunikacji ze swoim panem. Przekierowywanie FD-ów masterów było bezskuteczne, ponieważ dziecko odziedziczyło stderr, a zamknięcie standardowego potomka nie powiodło się dla mistrza, który czekał na drugim końcu rury. X- | Zanim spróbujesz tego, lepiej poznaj swoje procesy.
cmaster
@cmaster Możesz sprawdzić, czy uchwyt jest przekierowany za pomocą lsof(nazwa uchwytu pliku jest inna pipeniż /dev/pts/1) lub przez ls -l /proc/<PID>/fd/<fd>(pokazuje to dowiązanie symboliczne uchwytu). Również podprocesy nadal nie mogą przekierowywać danych wyjściowych, które powinny zostać przekierowane do pliku.
TrueY
7

Aby wysłać uruchomiony proces do nohup ( http://en.wikipedia.org/wiki/Nohup )

nohup -p pid , to nie zadziałało dla mnie

Następnie wypróbowałem następujące polecenia i zadziałało bardzo dobrze

  1. Powiedzmy, że uruchomcie SOMECOMMAND /usr/bin/python /vol/scripts/python_scripts/retention_all_properties.py 1.

  2. Ctrl+, Zaby zatrzymać (wstrzymać) program i wrócić do powłoki.

  3. bg aby uruchomić go w tle.

  4. disown -h aby proces nie został zabity, gdy terminal zostanie zamknięty.

  5. Wpisz, exitaby wyjść z powłoki, ponieważ teraz możesz zacząć, ponieważ operacja będzie działać w tle w swoim własnym procesie, więc nie jest związana z powłoką.

Ten proces jest równoważny z uruchomieniem nohup SOMECOMMAND.

minhas23
źródło
3

W moim systemie AIX próbowałem

nohup -p  processid>

To działało dobrze. Kontynuował mój proces nawet po zamknięciu okien terminala. Mamy domyślną powłokę ksh, więc polecenia bgi disownnie działały.

Gość
źródło
2
  1. ctrl+ z - spowoduje to wstrzymanie zadania (nie zostanie anulowane!)
  2. bg - spowoduje to umieszczenie zadania w tle i powrót do uruchomionego procesu
  3. disown -a - spowoduje to odcięcie całego załącznika z zadaniem (abyś mógł zamknąć terminal i nadal działać)

Te proste kroki pozwolą ci zamknąć terminal przy jednoczesnym zachowaniu procesu.

Nie nohupda się go założyć (w oparciu o moje rozumienie twojego pytania, nie potrzebujesz go tutaj).

Alper t. Turker
źródło
Myślę, że zachowanie disown -a polega na odcięciu przywiązania do wszystkich zadań. Jednak nie wyłącza potoków stdin / stdout, co oznacza, że ​​proces nadal będzie próbował pisać (/ czytać) z terminala
Kelthar
-2

To działało dla mnie na Ubuntu Linux w tcshell.

  1. CtrlZ wstrzymać to

  2. bg działać w tle

  3. jobs aby uzyskać numer zadania

  4. nohup %n gdzie n jest numerem zadania

eshaya
źródło
2
Nie, to nie działa:nohup: failed to run command '%1': No such file or directory
Dunatotatos