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

StackOverflow https://stackoverflow.com/questions/625409

  •  05-07-2019
  •  | 
  •  

Вопрос

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

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

Это было полезно?

Решение

Использование управления заданиями в bash для отправки процесса в фон:

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

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

    kill -SIGSTOP PID 
    kill -SIGCONT PID
    

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

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

    С bash-manpage (man bash):

      

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

         

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

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

    disown -a
    

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

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

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

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

    Проблема:

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

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

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

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

    nohup -p pid
    

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

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

    И теперь мы можем выйти из игры calling 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>
    

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

    В моей системе AIX я пробовал

    nohup -p  processid>
    

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

    <Ол>
  • ctrl + z - это приостановит работу (не отменять!)
  • bg - это переведет задание в фоновый режим и вернется в рабочий процесс
  • disown -a - это обрезает все вложения с заданием (так что вы можете закрыть терминал, и он все равно будет работать)
  • Эти простые шаги позволят вам закрыть терминал, продолжая процесс.

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

    Это сработало для меня в Ubuntu Linux, когда я был в tcshell.

    <Ол>
  • Ctrl Z , чтобы приостановить его

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

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

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

  • scroll top