Как поместить уже запущенный процесс в nohup? - PullRequest
865 голосов
/ 09 марта 2009

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

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

Ответы [ 10 ]

1277 голосов
/ 09 марта 2009

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

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

Предположим, по какой-то причине Ctrl + Z также не работает, перейдите на другой терминал, найдите идентификатор процесса (используя ps) и запустите:

kill -SIGSTOP PID 
kill -SIGCONT PID

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

84 голосов
/ 09 марта 2009

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

С bash-manpage (man bash):

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

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

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

disown -a

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

68 голосов
/ 19 ноября 2009

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

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

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

Проблема:

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

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

41 голосов
/ 17 марта 2013

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

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

nohup -p pid

См. http://en.wikipedia.org/wiki/Nohup

23 голосов
/ 10 октября 2014

Ответ узла действительно хорош, но он оставил открытым вопрос, как перенаправить 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 errno gdb.

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

COMMENT

Материал 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>

Надеюсь, это довольно полное описание решения.

7 голосов
/ 27 сентября 2013

Чтобы отправить запущенный процесс на 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.

2 голосов
/ 03 марта 2014

В моей системе AIX я пытался

nohup -p  processid>

Это сработало хорошо. Он продолжал запускать мой процесс даже после закрытия окон терминала. В качестве оболочки по умолчанию используется ksh, поэтому команды bg и disown не работают.

1 голос
/ 24 марта 2018
  1. ctrl + z - это приостановит работу (не отменять!)
  2. bg - это переведет задание в фоновый режим и вернется в рабочий процесс
  3. disown -a - это отрежет все вложения с заданием (так что вы можете закрыть терминал, и он все еще будет работать)

Эти простые шаги позволят вам закрыть терминал, продолжая процесс.

Он не наденет nohup (исходя из моего понимания вашего вопроса, он вам здесь не нужен).

0 голосов
/ 05 августа 2017

Это работало для меня на Ubuntu Linux, пока в Tcshell.

  1. Ctrl Z , чтобы приостановить его

  2. bg для запуска в фоновом режиме

  3. jobs, чтобы получить свой номер работы

  4. nohup %n где n - номер задания

...