Как поместить уже запущенный процесс в nohup?


940

У меня есть процесс, который уже запущен в течение длительного времени, и я не хочу его завершать.

Как поместить его в nohup (то есть, как заставить его продолжать работать, даже если я закрою терминал?)


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

Ответы:


1367

Использование Job Control в bash для отправки процесса в фоновый режим:

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

38
Поскольку вопрос заключался в том, как «поместить его в nohup», disown -hвозможно, более точный ответ: «заставить disown вести себя больше как nohup (то есть задания будут оставаться в дереве процессов вашей текущей оболочки до тех пор, пока вы не выйдете из нее). Это позволяет увидеть все работы, которые начались этой оболочкой ". (из [ quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/… )
д-р Ян-Филипп Герке

8
Как мне восстановить работу позже? Я вижу, как он работает, используя ps -e.
Пауло Касаретто

26
Вы не можете видеть выходные данные задания после того, как disown, 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.
Pungs

6
Также очень полезно, если задание запускается из другого сеанса SSH.
Амир Али Акбари

5
Просто не забудьте сделать disown %1в первом терминале, прежде чем закрывать его.
Фред

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

@fred Я этого не делал, и казалось, что он продолжает работать. Возможно или я нажал не тот PID?
Никто

91

Команда для отделения запущенного задания от оболочки (= делает его nohup) является disownи основной командой оболочки.

Из man-страницы bash (man bash):

отречься [-ar] [-h] [задание на работу ...]

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

Это означает, что простой

disown -a

удалит все задания из таблицы заданий и сделает их нету


9
disown -aудаляет все задания Простое disownудаляет только текущую работу. Как говорится в справочной странице в ответе.
Руна Шеллеруп Философ

73

Это хорошие ответы выше, я просто хотел добавить пояснение:

Вы не можете disownпид или процесс, вы disownработа, и это важное различие.

Задание - это то, что является понятием процесса, прикрепленного к оболочке, поэтому вы должны выбросить задание в фоновый режим (не приостанавливать его), а затем отказаться от него.

Выпуск:

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

См. Http://www.quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/jobcontrol/ для более подробного обсуждения Unix Job Control.


48

К сожалению, disownэто специфично для bash и доступно не во всех оболочках.

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

nohup -p pid

Смотрите http://en.wikipedia.org/wiki/Nohup


Только для AIXа Solaris. «Версии nohup в AIX и Solaris имеют опцию -p, которая изменяет запущенный процесс, игнорируя будущие сигналы SIGHUP. В отличие от описанного выше встроенного в bash disown, nohup -p принимает идентификаторы процессов». Источник
АликЭльзин-килака

27

Ответ Node действительно хорош, но он оставил открытым вопрос, как перенаправить stdout и stderr. Я нашел решение для Unix и Linux , но оно также не завершено. Я хотел бы объединить эти два решения. Вот:

Для своего теста я создал небольшой скрипт bash, называемый loop.sh, который печатает pid самого себя с минутным сном в бесконечном цикле.

$./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

Close (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("")выводит сообщение об ошибке. Если нам нужна ошибка, используйте команду p errnogdb.

Теперь мы можем проверить вновь перенаправленный файл. /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

И теперь мы можем выйти из вызывающего bash. Процесс продолжается в фоновом режиме. Если мы выйдем, его 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 для связи со своим хозяином. Перенаправление основных FD хозяев было безрезультатным, потому что дочерний процесс унаследовал stderr, а закрытие дочернего стандартного вывода не удалось запустить мастер, ожидающий на другом конце канала. Х- | Лучше знать ваши процессы, прежде чем вы попробуете это.
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, поэтому команды bgand 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
Dunatotatos
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.