In Linux, how to prevent a background process from being stopped after closing SSH client

Я работаю на машине Linux через SSH (Putty). Мне нужно оставить процесс работающим ночью, поэтому я подумал, что смогу сделать это, запустив процесс в фоновом режиме (с амперсандом в конце команды) и перенаправив стандартный вывод в файл. К моему удивлению, это не работает. Как только я закрываю окно Putty, процесс останавливается.

Как я могу предотвратить это?

20 ответов

Решение

Проверьте программу " nohup".

Я бы порекомендовал использовать GNU Screen. Это позволяет вам отключиться от сервера, пока все ваши процессы продолжают работать. Я не знаю, как я жил без этого, прежде чем я знал, что это существует.

Когда сессия закрыта, процесс получает сигнал SIGHUP, который он явно не перехватывает. Вы можете использовать nohup команда при запуске процесса или встроенная команда bash disown -h после запуска процесса, чтобы предотвратить это:

> help disown
disown: disown [-h] [-ar] [jobspec ...]
     By default, removes each JOBSPEC argument from the table of active jobs.
    If the -h option is given, the job is not removed from the table, but is
    marked so that SIGHUP is not sent to the job if the shell receives a
    SIGHUP.  The -a option, when JOBSPEC is not supplied, means to remove all
    jobs from the job table; the -r option means to remove only running jobs.

Демон? поЬир? SCREEN? (tmux ftw, экран мусорный;-)

Просто сделайте то, что делало любое другое приложение с самого начала - двойную вилку.

# ((exec sleep 30)&)
# grep PPid /proc/`pgrep sleep`/status
PPid:   1
# jobs
# disown
bash: disown: current: no such job

Взрыв! Готово:-) Я использовал это бесчисленное количество раз на всех типах приложений и на многих старых машинах. Вы можете комбинировать с перенаправлениями и так далее, чтобы открыть частный канал между вами и процессом.

Создайте как coproc.sh:

#!/bin/bash

IFS=

run_in_coproc () {
    echo "coproc[$1] -> main"
    read -r; echo $REPLY
}

# dynamic-coprocess-generator. nice.
_coproc () {
    local i o e n=${1//[^A-Za-z0-9_]}; shift
    exec {i}<> <(:) {o}<> >(:) {e}<> >(:)
. /dev/stdin <<COPROC "${@}"
    (("\$@")&) <&$i >&$o 2>&$e
    $n=( $o $i $e )
COPROC
}

# pi-rads-of-awesome?
for x in {0..5}; do
    _coproc COPROC$x run_in_coproc $x
    declare -p COPROC$x
done

for x in COPROC{0..5}; do
. /dev/stdin <<RUN
    read -r -u \${$x[0]}; echo \$REPLY
    echo "$x <- main" >&\${$x[1]}
    read -r -u \${$x[0]}; echo \$REPLY
RUN
done

а потом

# ./coproc.sh 
declare -a COPROC0='([0]="21" [1]="16" [2]="23")'
declare -a COPROC1='([0]="24" [1]="19" [2]="26")'
declare -a COPROC2='([0]="27" [1]="22" [2]="29")'
declare -a COPROC3='([0]="30" [1]="25" [2]="32")'
declare -a COPROC4='([0]="33" [1]="28" [2]="35")'
declare -a COPROC5='([0]="36" [1]="31" [2]="38")'
coproc[0] -> main
COPROC0 <- main
coproc[1] -> main
COPROC1 <- main
coproc[2] -> main
COPROC2 <- main
coproc[3] -> main
COPROC3 <- main
coproc[4] -> main
COPROC4 <- main
coproc[5] -> main
COPROC5 <- main

И там вы идете, икру что угодно. <(:) открывает анонимный канал через подстановку процесса, которая умирает, но канал остается на месте, потому что у вас есть дескриптор. Я обычно делаю sleep 1 вместо : потому что он немного грубый, и я получаю ошибку "file busy" - никогда не произойдет, если будет запущена настоящая команда (например, command true)

"Heredoc Sourcing":

. /dev/stdin <<EOF
[...]
EOF

Это работает на каждой оболочке, которую я когда-либо пробовал, включая busybox/etc (initramfs). Я никогда не видел, чтобы это было сделано раньше, я самостоятельно обнаружил это, подталкивая, кто знал, что источник может принимать аргументы? Но это часто служит гораздо более управляемой формой оценки, если такая вещь существует.

nohup blah &

Замените имя вашего процесса на бла!

Лично мне нравится команда "партия".

$ batch
> mycommand -x arg1 -y arg2 -z arg3
> ^D

Это заполняет его на задний план, а затем отправляет результаты по почте вам. Это часть cron.

Для большинства процессов вы можете псевдо-демонизировать, используя этот старый трюк командной строки Linux:

# ((mycommand &)&)

Например:

# ((sleep 30 &)&)
# exit

Затем запустите новое окно терминала и:

# ps aux | grep sleep

Покажет что sleep 30 все еще работает.

Что вы сделали, так это запустили процесс, будучи ребенком ребенка, и когда вы выходите, nohup Команда, которая обычно запускает процесс для выхода, не распространяется на внучат, оставляя его как процесс-сирота, все еще работающий.

Я предпочитаю такой подход "установи и забудь", не нужно иметь дело с nohup, screen, tmux, перенаправление ввода / вывода или что-то в этом роде.

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

Вы можете найти информацию о демонизирующих процессах в книгах, таких как "Расширенная сетевая программа Стивенса", том 1, 3-й Эдн "или" Расширенное программирование Unix "Рочкинда.

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

Usage: daemonize [-abchptxV][-d dir][-e err][-i in][-o out][-s sigs][-k fds][-m umask] -- command [args...]
  -V          print version and exit
  -a          output files in append mode (O_APPEND)
  -b          both output and error go to output file
  -c          create output files (O_CREAT)
  -d dir      change to given directory
  -e file     error file (standard error - /dev/null)
  -h          print help and exit
  -i file     input file (standard input - /dev/null)
  -k fd-list  keep file descriptors listed open
  -m umask    set umask (octal)
  -o file     output file (standard output - /dev/null)
  -s sig-list ignore signal numbers
  -t          truncate output files (O_TRUNC)
  -p          print daemon PID on original stdout
  -x          output files must be new (O_EXCL)

Двойная черта не обязательна в системах, не использующих функцию GNU getopt(); это необходимо (или вы должны указать POSIXLY_CORRECT в среде) в Linux и т. д. Поскольку двойная черта работает везде, лучше всего ее использовать.

Вы все еще можете связаться со мной (имя, точка, фамилия на gmail, точка com), если вы хотите, чтобы источник daemonize,

Тем не менее, код теперь (наконец) доступен на GitHub в моем хранилище SOQ (вопросы о переполнении стека) в виде файла daemonize-1.10.tgz в подкаталоге пакетов.

В системе на основе Debian (на удаленной машине) Установите:

sudo apt-get установить tmux

Использование:

tmux

запустить команды, которые вы хотите

Чтобы переименовать сессию:

Ctrl + B, затем $

Имя набора

Чтобы выйти из сеанса:

Ctrl + B, затем D

(это оставляет сеанс tmux). Затем вы можете выйти из SSH.

Когда вам нужно вернуться / проверить это снова, запустите SSH и введите

tmux прикрепить имя_сессии

Это вернет вас к сеансу tmux.

nohup очень хорошо, если вы хотите записать свои данные в файл. Но когда дело доходит до фона, вы не можете дать ему пароль, если ваши скрипты просят. Я думаю, что вы должны попробовать screen, это утилита, которую вы можете установить в свой дистрибутив Linux, используя yum, например, для CentOS yum install screen затем получить доступ к вашему серверу с помощью замазки или другого программного обеспечения, в вашем типе оболочки screen, Откроется экран [0] в замазке. Ты работаешь. Вы можете создать больше экрана [1], экрана [2] и т. Д. В одном сеансе замазки.

Основные команды, которые вам нужно знать:

Для запуска экрана

экран


Чтобы создать следующий экран

Ctrl+ A + C


Для перехода на новый экран, который вы создали

Ctrl+ A + N


Чтобы быть

Ctrl+ A + D


Во время работы закройте замазку. И в следующий раз, когда вы входите через тип замазки

экран -r

Для повторного подключения к экрану, и вы можете увидеть, что ваш процесс все еще работает на экране. И для выхода из экрана наберите #exit.

Для более подробной информации смотрите man screen,

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

nohup /bin/sh -c "echo \$\$ > $pidfile; exec $FOO_BIN $FOO_CONFIG  " > /dev/null

Nohup делает процесс, который вы запускаете, невосприимчивым к прекращению, которое сеанс SSH и его дочерние процессы уничтожают при выходе из системы. Команда, которую я дал, предоставляет вам способ сохранить pid приложения в pid-файле, чтобы вы могли корректно убить его позже и позволить процессу запускаться после выхода из системы.

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

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

Используйте экран. Он очень прост в использовании и работает как vnc для терминалов. http://www.bangmoney.org/presentations/screen.html

Также есть команда daemon из пакета с открытым исходным кодом libslack.

daemon вполне настраивается и заботится обо всех утомительных вещах демона, таких как автоматический перезапуск, ведение журнала или обработка pidfile.

Принятый ответ предлагает использовать nohup. Я бы скорее предложил использовать pm2. Использование pm2 по сравнению с nohup имеет много преимуществ, таких как поддержание приложения в рабочем состоянии, поддержка файлов журналов для приложения и множество других функций. Для более подробной информации проверьте это.

Для установки pm2 необходимо скачать npm. Для системы на основе Debian

sudo apt-get install npm

и для Redhat

sudo yum install npm

Или вы можете следовать этим инструкциям. После установки npm используйте его для установки pm2

npm install pm2@latest -g

Как только это будет сделано, вы можете начать свое приложение по

$ pm2 start app.js              # Start, Daemonize and auto-restart application (Node)
$ pm2 start app.py              # Start, Daemonize and auto-restart application (Python)

Для мониторинга процесса используйте следующие команды:

$ pm2 list                      # List all processes started with PM2
$ pm2 monit                     # Display memory and cpu usage of each app
$ pm2 show [app-name]           # Show all informations about application

Управляйте процессами, используя имя приложения или идентификатор процесса, или управляйте всеми процессами вместе:

$ pm2 stop     <app_name|id|'all'|json_conf>
$ pm2 restart  <app_name|id|'all'|json_conf>
$ pm2 delete   <app_name|id|'all'|json_conf>

Файлы журналов можно найти в

$HOME/.pm2/logs #contain all applications logs

Двоичные исполняемые файлы также могут быть запущены с использованием pm2. Вы должны внести изменения в файл Джейсона. Изменить "exec_interpreter" : "node", чтобы "exec_interpreter" : "none". (см. раздел атрибутов).

#include <stdio.h>
#include <unistd.h>  //No standard C library
int main(void)
{
    printf("Hello World\n");
    sleep (100);
    printf("Hello World\n");

    return 0;
}

Компиляция кода выше

gcc -o hello hello.c  

и запустить его с np2 в фоновом режиме

pm2 start ./hello

Если вы также хотите запускать X-приложения - используйте xpra вместе с "screen".

Я также хотел бы пойти на экран программы (я знаю, что еще один ответ был экран, но это завершение)

не только тот факт, что &, ctrl+z bg disown, nohup и т. д. может преподнести вам неприятный сюрприз, что когда вы выйдете из системы, работа все равно будет убита (я не знаю почему, но это случилось со мной, и это не беспокоило это потому, что я переключился на использование экрана, но я думаю, что решение anthonyrisinger, поскольку двойное разветвление решило бы это), также экран имеет большое преимущество по сравнению с просто отступлением:

screen will background your process without losing interactive control to it

и кстати, это вопрос, который я бы никогда не задал в первую очередь:) ... я использую screen с самого начала, чтобы что-то делать в любом unix ... я (почти) НИКОГДА не работаю в оболочке unix/linux без начального экрана сначала... и я должен остановиться сейчас, или я начну бесконечное представление о том, что такое хороший экран и что может для вас сделать... посмотрите сами, оно того стоит;)

Добавьте эту строку в вашу команду:> & - 2> & - <& - &. >& - означает закрытие стандартного вывода. 2>&- означает закрыть stderr. <& - означает закрытие стандартного ввода. & означает запуск в фоновом режиме. Это также работает для программного запуска задания через ssh:

$ ssh myhost 'sleep 30 >&- 2>&- <&- &'
# ssh returns right away, and your sleep job is running remotely
$

Я использовал экранную команду. Эта ссылка подробно о том, как это сделать

https://www.rackaid.com/blog/linux-screen-tutorial-and-how-to/

В systemd/Linux systemd-run - хороший инструмент для запуска независимых от сессии процессов. Ненавистники пусть ненавидят

Другие вопросы по тегам