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?)
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?)
Odpowiedzi:
Korzystanie z kontroli zadań bash, aby wysłać proces w tle:
bg
aby uruchomić go w tle.disown -h [job-spec]
gdzie [specyfikacja zadania] to numer zadania (jak %1
dla pierwszego uruchomionego zadania; znajdź swój numer za pomocą jobs
polecenia), aby zadanie nie zostało zabite, gdy terminal zostanie zamknięty.disown -h
być 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/… )
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
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
SIGSTOP
zawiesi proces i SIGCONT
wznowi proces w tle. Więc teraz zamknięcie obu terminali nie zatrzyma twojego procesu.
disown %1
w pierwszym terminalu przed jego zamknięciem.
kwin
po 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
!
Polecenie oddzielenia uruchomionego zadania od powłoki (= powoduje, że nie jest to żadna czynność) jest disown
podstawowym 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ć
disown -a
usuwa wszystkie zadania. Prosty disown
usuwa tylko bieżące zadanie. Jak mówi strona podręcznika w odpowiedzi.
Oto dobre odpowiedzi powyżej, chciałem tylko dodać wyjaśnienie:
Nie możesz disown
płacić ani przetwarzać, jesteś disown
pracą, 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.
Niestety disown
jest specyficzny dla bash i nie jest dostępny we wszystkich powłokach.
Niektóre warianty Uniksa (np. AIX i Solaris) mają opcję w nohup
samej komendzie, którą można zastosować do uruchomionego procesu:
nohup -p pid
AIX
i 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
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.sh
jest 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 gdb
należ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 STAT
pole 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_WRONLY
można zastosować, ale /usr/sbin/lsof
mówi „u” dla wszystkich procedur obsługi plików std * ( FD
kolumna), 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 nohup
przypadku, 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 errno
gdb.
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 bash
musi zostać zwolniony i możemy wyjść gdb
:
(gdb) detach
Detaching from program: /bin/bash, process <PID>
(gdb) q
Jeśli skrypt został zatrzymany przez gdb
inny 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 ^Z
na 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 jobs
wynikach polecenia w nawiasach kwadratowych oznacza zadanie wewnątrz bash
. Możemy użyć następujących wbudowanych bash
poleceń, 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.
lsof
(nazwa uchwytu pliku jest inna pipe
niż /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.
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
Powiedzmy, że uruchomcie SOMECOMMAND /usr/bin/python /vol/scripts/python_scripts/retention_all_properties.py 1
.
Ctrl+, Zaby zatrzymać (wstrzymać) program i wrócić do powłoki.
bg
aby uruchomić go w tle.
disown -h
aby proces nie został zabity, gdy terminal zostanie zamknięty.
Wpisz, exit
aby 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
.
bg
- spowoduje to umieszczenie zadania w tle i powrót do uruchomionego procesudisown -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 nohup
da się go założyć (w oparciu o moje rozumienie twojego pytania, nie potrzebujesz go tutaj).
To działało dla mnie na Ubuntu Linux w tcshell.
CtrlZ wstrzymać to
bg
działać w tle
jobs
aby uzyskać numer zadania
nohup %n
gdzie n jest numerem zadania
nohup: failed to run command '%1': No such file or directory
yourExecutable &
a wyniki wciąż pojawiają się na ekranie iCtrl+C
nie wydają się niczego zatrzymywać, po prostu ślepo wpiszdisown;
i naciśnij,Enter
nawet 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.