Linux

Как предотвратить остановку фонового процесса после закрытия клиента SSH в Linux

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

К моему удивлению, это не работает. Как только я закрываю окно Putty, процесс останавливается.

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

 

Ответ 1

Просто сделайте то, что делали все остальные приложения с самого начала double fork.

# ((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, вместо «:», потому что это немного некрасиво, и я получу ошибку "файл занят" - этого никогда не происходит, если выполняется настоящая команда (например, command true).

"heredoc sourcing":

. /dev/stdin <<EOF

[...]

EOF

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

 

Ответ 2

Как отмечали другие, для запуска процесса в фоновом режиме, чтобы вы могли отключиться от сеанса SSH, вам нужно, чтобы фоновый процесс правильно отсоединился от своего управляющего терминала псевдо-tty, который использует сеанс SSH. Информацию о демонизации процессов можно найти в таких книгах, как Stevens "Advanced Network Program, Vol 1, 3rd Edn" или Rochkind "Advanced Unix Programming". Недавно (за последние пару лет) мне пришлось иметь дело с непокорной программой, которая не даемонизировала себя должным образом. В итоге я решил эту проблему, создав общую программу демонизации похожую на nohup, но с более широкими возможностями управления.

USAGE: daemonize [-abchptxV][-d dir][-e err][-i in][-o out][-s sigs][-k fds][-m umask] -- command [args...]

  -V вывести версию и выйти;

  -a выводить файлы в режиме добавления (O_APPEND);

  -b и вывод, и ошибка идут в выходной файл;

  -c создать выходные файлы (O_CREAT);

  -d dir переход в заданный каталог;

  -e файл ошибки (стандартная ошибка - /dev/null);

  -h вывести справку и выйти

  -i file входной файл (стандартный ввод - /dev/null);

  -k fd-list вести список открытых дескрипторов файлов;

  -m umask установить umask (восьмеричный);

  -o file выходной файл (стандартный вывод - /dev/null);

  -s sig-list игнорировать номера сигналов;

  -t усекать выходные файлы (O_TRUNC);

  -p вывести PID демона на исходный stdout;

  -x выходные файлы должны быть новыми (O_EXCL).

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


Ответ 3

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

# ((mycommand &)&)

Например:

# ((sleep 30 &)&)

# exit

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

# ps aux | grep sleep.

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

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

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

 

Ответ 4

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

 

Схожие статьи

Linux

Как получить информацию о только что запущенном процессе

Linux

Существующие решения, позволяющие использовать контроль версий для файлов конфигурации сервера

Linux

Как определить объем использованной памяти и среднюю нагрузку на Linux-сервере?

Linux

Как запустить процесс Node.js в фоновом режиме и запретить его завершение