Як помістити вже запущений процес під nohup?


940

У мене процес, який вже триває, і не хочу його закінчувати.

Як помістити його під nohup (тобто як змусити його продовжувати працювати, навіть якщо закрити термінал?)


29
Для всіх, хто стикається з тією самою проблемою: Пам’ятайте, що навіть якщо ви вводите yourExecutable &і виходи продовжують надходити на екран і Ctrl+C, здається, нічого не зупиняють, просто сліпо введіть disown;і натисніть, Enterнавіть якщо екран прокручується з виходами, і ви не бачите, що ти друкуєш. Процес буде відмовлено, і ви зможете закрити термінал, не вмираючи.
Nav

Відповіді:


1367

Використання керування роботою bash для надсилання процесу на задній план:

  1. Ctrl+ Zзупинити (призупинити) програму і повернутися до оболонки.
  2. bg запустити його у фоновому режимі.
  3. disown -h [job-spec]де [job-spec] - номер завдання (як %1для першого запущеного завдання; знайдіть про свій номер за допомогою jobsкоманди), щоб завдання не загинуло, коли термінал закривається.

38
Оскільки питання полягав у тому, як "поставити його під ногуп", disown -hможливо, є більш точна відповідь: "змусити відхреститися поводитись більше, як нохуп (тобто завдання залишатимуться у вашому поточному дереві обробки оболонки до виходу з оболонки). Це дозволяє вам побачити усі завдання, які розпочала ця оболонка ". (від [ quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/… )
доктор Ян-Філіп Геррк

8
Як пізніше відновити роботу? Я бачу, як це працює за допомогою ps -e.
Пауло Касаретто

26
Ви не можете побачити вихід завдання після a disown, відключення робить процес демон, а це означає, що стандартні введення / виведення перенаправляються на / dev / null. Отже, якщо ви плануєте відмовитись від роботи, краще розпочати її з входу у файл, наприкладmy_job_command | tee my_job.log
rustyx

8
чи можна якось зробити щось на кшталт 'my_job_command | tee my_job.log ' після того, як команда вже запущена?
арод

23
disownвідключає будь-які труби від процесу. Для повторного приєднання труб використовуйте, gdbяк описано в цій нитці . Більш конкретно, це повідомлення .
mbrownnyc

185

Припустимо, чомусь Ctrl+ Zтеж не працює, перейдіть до іншого терміналу, знайдіть ідентифікатор процесу (використовуючи ps) та запустіть:

kill -SIGSTOP PID 
kill -SIGCONT PID

SIGSTOPпризупинить процес і SIGCONTвідновить процес у фоновому режимі. Тож закриття обох терміналів не зупинить ваш процес.


10
Так, ця проблема ОС, kill не працює з Cygwin у Windows.
Пунгс

6
Також дуже корисно, якщо завдання розпочато з іншого сеансу ssh.
Амір Алі Акбарі

5
Просто пам’ятайте, що потрібно зробити disown %1в першому терміналі, перш ніж закривати його.
fred

1
Це корисно, оскільки я запустив графічний інтерфейс з консоллю (в моєму випадку я починав з konsole kwinпісля аварії, не думаючи про наслідки). Тож якби я зупинив kwin, усе б замерзло і я не мав би можливості бігати bg!
Мішель

@fred Я цього не робив і, здавалося, продовжував працювати. Можливо чи я потрапив неправильно PID?
Ніхто

91

Команда відокремити запущене завдання від оболонки (= робить його nohup) є disownбазовою командою shell.

З bash-manpage (man bash):

відрікся [-ar] [-h] [jobspec ...]

Без опцій кожен спецзапис видаляється з таблиці активних завдань. Якщо параметр -h заданий, кожен параметр jobs не видаляється з таблиці, але позначається таким чином, що SIGHUP не надсилається до завдання, якщо оболонка отримує SIGHUP. Якщо немає робочих параметрів, і не надається опція -a, або -r, використовується поточне завдання. Якщо не вказано жодного робочого місця, опція -a означає видалити або позначити всі завдання; опція -r без аргументу jobspec обмежує роботу запущеними завданнями. Повернене значення дорівнює 0, якщо у специфікації jobs не вказано дійсне завдання.

Це означає, що простий

disown -a

видалить усі завдання з таблиці завдань і зробить їх відсутніми


9
disown -aвидаляє всі завдання. Простий disownлише видаляє поточну роботу. Як говорить сторінка людини у відповіді.
Rune Schjellerup Philosof

73

Це хороші відповіді вище, я просто хотів додати уточнення:

Ви не disownможете підписати чи обробити, тиdisown працюєте, і це важлива відмінність.

Завдання - це поняття про процес, який прикріплений до оболонки, тому ви повинні відкинути роботу на другий план (не призупиняти її), а потім відхилити її.

Проблема:

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

Дивіться http://www.quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/jobcontrol/ для більш детального обговорення управління роботою Unix.


48

На жаль, disown є специфічним для bash і доступний не у всіх оболонках.

Окремі аромати Unix (наприклад, AIX та Solaris) мають можливість самої nohupкоманди, яку можна застосувати до запущеного процесу:

nohup -p pid

Дивіться http://en.wikipedia.org/wiki/Nohup


Тільки для AIXі Solaris. "AIX і Solaris версії nohup мають опцію -p, яка модифікує запущений процес, щоб ігнорувати майбутні сигнали SIGHUP. На відміну від вищеописаного відключення, побудованого в bash, nohup -p приймає ідентифікатори процесу." Джерело
AlikElzin-kilaka

27

Відповідь Вузла дійсно чудова, але вона залишила відкритим питання про те, як можна перенаправити stdout та stderr. Я знайшов рішення на Unix & Linux , але воно також не є повним. Я хотів би об'єднати ці два рішення. Ось:

Для мого тесту я створив невеликий скрипт bash під назвою loop.sh, який друкує під себе під час хвилинного сну у нескінченному циклі.

$./loop.sh

Тепер якось отримайте PID цього процесу. Зазвичайps -C loop.sh це досить добре, але він друкується в моєму випадку.

Тепер ми можемо перейти на інший термінал (або натиснути ^ Z і в цьому ж терміналі). Тепер gdbдо цього процесу слід долучитись.

$ gdb -p <PID>

Це зупиняє сценарій (якщо він працює). Його стан можна перевірити ps -f <PID>, де STATполем є "T +" (або у випадку ^ Z 'T'), що означає (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

Закрити (1) повертає нуль на успіх.

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

Open (1) у разі успіху повертає новий дескриптор файлу.

Цей відкритий дорівнює open(path, O_TRUNC|O_CREAT|O_RDWR, S_IRUSR|S_IWUSR). Замість цього O_RDWR O_WRONLYможна застосувати, але /usr/sbin/lsofкаже "u" для всіх файлових файлів std * ( FDстовпець), що єO_RDWR .

Я перевірив значення у файлі заголовка /usr/include/bits/fcntl.h.

Вихідний файл можна було б відкрити за допомогою O_APPEND, як це nohupбуло б зроблено, але це не пропонуєтьсяman open(2) через можливі проблеми з NFS.

Якщо ми отримаємо -1 як зворотне значення, то call perror("")надрукуємо повідомлення про помилку. Якщо нам потрібна errno, використовуйте p errnogdb comand.

Тепер ми можемо перевірити нещодавно перенаправлений файл. /usr/sbin/lsof -p <PID>відбитки:

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

Якщо ми хочемо, ми можемо перенаправити stderr до іншого файлу, якщо ми хочемо використовувати call close(2)та call open(...)знову використовувати інше ім’я файлу.

Тепер додаток bashмає бути звільнено, і ми можемо вийти gdb:

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

Якщо скрипт був зупинений gdbз іншого терміналу, він продовжує працювати. Ми можемо повернутися до терміналу loop.sh. Тепер він нічого не пише на екран, а працює і записує у файл. Треба відкласти це на другий план. Тож натисніть ^Z.

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

(Зараз ми перебуваємо в тому ж стані, як ніби ^Zнатискали на початку.)

Тепер ми можемо перевірити стан роботи:

$ 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

Тому процес повинен працювати у фоновому режимі та відірватися від терміналу. Число у jobsвиведенні команди у квадратних дужках ідентифікує завдання всередині bash. Ми можемо використовувати в наступних вбудованих bashкомандах, що застосовують знак "%" перед номером завдання:

$ 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

А тепер ми можемо вийти з виклику баш. Процес продовжується у фоновому режимі. Якщо ми припинимо його PPID, стаємо 1 (init (1) процес), а термінал управління стане невідомим.

$ 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)

КОМЕНТАР

Ресурси gdb можна автоматизувати, створивши файл (наприклад, loop.gdb), що містить команди та запустити gdb -q -x loop.gdb -p <PID>. Мій loop.gdb виглядає так:

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

Або замість цього можна використовувати наступний вкладиш:

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

Я сподіваюся, що це досить повний опис рішення.


Дійсно, дуже інформативно, і, ймовірно, спрацює добре у простих випадках. Але будьте попереджені, складніші випадки можуть нещасно провалитися. Я мав один із таких сьогодні: мій процес породив ще один процес, який робив вихід (імовірно, на stderr), але stdout підключився для спілкування зі своїм господарем. Перенаправлення майстер-дисків було безрезультатним, оскільки дитина отримала спадщину більш жорстким, а закриття дитячого виводу не вдалося майстру, який чекав на іншому кінці труби. X- | Краще знайте свої процеси, перш ніж спробувати це.
cmaster - відновити моніку

@cmaster Ви можете перевірити, чи ручка перенаправлена ​​за допомогою lsof(ім'я файлу файлу - pipeне так /dev/pts/1) або за допомогою ls -l /proc/<PID>/fd/<fd>(це показує символьне посилання ручки). Також підпроцеси все ще не можуть мати перенаправлені виходи, які слід переспрямувати у файл.
TrueY

7

Надіслати запущений процес до nohup ( http://en.wikipedia.org/wiki/Nohup )

nohup -p pid , це не працювало для мене

Тоді я спробував наступні команди, і це спрацювало дуже добре

  1. Запустіть якусь SOMECOMMAND, скажімо /usr/bin/python /vol/scripts/python_scripts/retention_all_properties.py 1.

  2. Ctrl+ Zзупинити (призупинити) програму і повернутися до оболонки.

  3. bg запустити його у фоновому режимі.

  4. disown -h щоб процес не загинув, коли термінал закривається.

  5. Введіть, exitщоб вийти з оболонки, тому що тепер вам добре працювати, оскільки операція буде виконуватись у фоновому режимі у своєму процесі, тому вона не прив’язана до оболонки.

Цей процес є еквівалентом запущеного nohup SOMECOMMAND.


3

На своїй системі AIX я спробував

nohup -p  processid>

Це добре спрацювало. Він продовжував запускати мій процес навіть після закриття вікон терміналу. У нас є ksh як оболонка за замовчуванням, тому команди bgта disownкоманди не працюють.


2
  1. ctrl+ z - це призупинить роботу (не збирається скасовувати!)
  2. bg - це поставить завдання на другий план і повернеться в запущений процес
  3. disown -a - це скоротить усе вкладення з роботою (так що ви можете закрити термінал, і він все ще буде працювати)

Ці прості дії дозволять вам закрити термінал, зберігаючи процес.

Це не буде покладене nohup(на основі мого розуміння вашого питання, вам це не потрібно тут).


Я думаю, що поведінка для відмови - це скоротити прихильність до всіх робочих місць. Однак він не вимикає трубопроводи stdin / stdout, а це означає, що процес все ще намагатиметься записати (/ прочитати) з терміналу
Kelthar

-2

Це працювало для мене на Ubuntu linux під час роботи в tcshell.

  1. CtrlZ призупинити його

  2. bg бігати у фоновому режимі

  3. jobs щоб отримати його номер роботи

  4. nohup %n де n - номер роботи


2
Ні, це не працює:nohup: failed to run command '%1': No such file or directory
Дунатотатос
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.