Я работаю на машине 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