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?

Для чего нужны открытые CAD программы для Linux, какие они бывают
Linux

Для чего нужны открытые CAD программы для Linux, какие они бывают

Linux

Как сделать так, чтобы дочерний процесс завершался после завершения родительского

Linux

Как предотвратить изменение пароля root в Linux?

×