如何防止Linux操作系统关闭SSH客户端后后台进程被停止

我正在通过SSH (Putty)在Linux机器上工作。我需要让一个进程在夜间运行,因此我认为可以通过在后台启动该进程(在命令末尾使用&号)并将stdout重定向到一个文件来实现这一点。

令我惊讶的是,这行不通。只要我关闭Putty窗口,进程就会停止。

我怎样才能防止这种情况发生?

238826 次浏览

查看“nohup”程序。

我建议使用GNU屏幕。它允许您在所有进程继续运行时断开与服务器的连接。在我知道它存在之前,我不知道没有它是怎么生活的。

< p >使用屏幕。它使用起来非常简单,就像终端的vnc一样。 http://www.bangmoney.org/presentations/screen.html < / p >

当会话关闭时,进程接收到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.
nohup blah &

用您的进程名替换blah!

如果父进程被杀死,Nohup允许不杀死客户端进程,以便在注销时进行论证。更好的用法是:

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

Nohup使您启动的进程不受终止的影响,当您退出时,SSH会话及其子进程将被终止。我给出的命令提供了一种方法,可以将应用程序的pid存储在pid文件中,以便稍后正确地终止它,并允许进程在注销后运行。

正如其他人所指出的,要在后台运行进程以便与SSH会话断开连接,您需要让后台进程正确地与它的控制终端断开关联——这是SSH会话使用的伪tty。

您可以在Stevens的“高级网络程序,第1卷,第3版”或Rochkind的“高级Unix编程”等书籍中找到有关守护进程的信息。

最近(在过去的几年里),我不得不处理一个不听话的程序,它没有正确地守护自己。最后,我创建了一个通用的daemonizing程序来解决这个问题——类似于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()函数的系统上,双破折号是可选的;这在Linux等环境中是必要的(或者你必须在环境中指定POSIXLY_CORRECT)。由于双破折号在任何地方都适用,所以最好使用它。

如果你想要daemonize的源代码,你仍然可以联系我(firstname . lastname at gmail.com)。

然而,代码现在(终于)可在GitHub在我的SOQ(堆栈 的daemonize-1.10.tgz文件 子目录。< / p >

如果使用screen作为根用户运行进程,请注意特权提升攻击的可能性。如果你自己的帐户以某种方式被泄露,将有一种直接的方式接管整个服务器。

如果需要定期运行此进程,并且您对服务器有足够的访问权限,那么更好的选择是使用cron来运行该作业。你也可以使用init。D(超级守护进程)在后台启动您的进程,并且它可以在完成后立即终止。

就我个人而言,我喜欢“batch”命令。

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

这将把它塞到后台,然后将结果邮寄给你。这是cron的一部分。

如果你想同时运行X个应用程序,可以使用xpra和"screen"。

daemonize吗?nohup吗?屏幕?(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

这就是,衍生什么的。The <(:)通过进程替换打开一个匿名管道,这个过程结束了,但是管道仍然存在,因为你有它的句柄。我通常做sleep 1而不是:,因为它有点不正常,我会得到一个“文件繁忙”错误——如果运行一个真正的命令(例如,command true),永远不会发生。

“heredoc采购”:

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

这适用于我尝试过的每一个shell,包括busybox/etc (initramfs)。我以前从未见过这种情况,我是自己发现的,谁知道来源可以接受args呢?但它通常是一种更易于管理的计算形式,如果有的话。

我也会去屏幕程序(我知道some1其他答案是屏幕,但这是一个完成)

事实不仅是&, ctrl+z bg disown, nohup等可能会给你一个讨厌的惊喜,当你退出工作仍然会被杀死(我不知道为什么,但它发生在我身上,它没有打扰它,因为我切换到使用屏幕,但我猜anthonyrisinger解决方案作为双分叉将解决这个问题),而且屏幕有一个主要的优势,而不是仅仅后台:

screen will background your process without losing interactive control to it

顺便说一句,这是一个我一开始就不会问的问题:)…我从一开始在Unix上做任何事情就使用screen…我(几乎)从未在unix/linux shell中工作而不首先开始屏幕…我现在应该停止了,否则我将开始无休止的演示什么是好屏幕以及可以为你们做什么……自己去查吧,很值得的;)

还有开源libslack包的守护进程命令。

daemon是相当可配置的,并且关心所有繁琐的守护进程的东西,如自动重启、日志记录或pidfile处理。

将此字符串附加到您的命令:>&- 2>&- <&- &>&-表示关闭标准输出。2>&-关闭stderr。<&-表示关闭stdin。,意味着在后台运行。这也可以通过ssh以编程方式启动作业:

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

nohup是非常好的,如果你想把你的详细信息记录到一个文件。但当它进入后台时,如果你的脚本要求,你无法给它一个密码。我认为你必须尝试screen。它是一个实用工具,你可以在linux发行版上使用yum安装,例如在CentOS yum install screen上,然后通过putty或其他软件访问你的服务器,在你的shell类型screen中。它将打开屏幕[0]在腻子。做好你的工作。你可以在同一个putty会话中创建更多的screen[1], screen[2]等。

你需要知道的基本命令:

启动屏幕

屏幕


create下一个屏幕

ctrl + a + c


移动到你创建的next屏幕

ctrl + a + n


detach

ctrl + a + d


在工作期间关闭腻子。下次当你登录通过putty类型

屏幕- r

重新连接到屏幕,您可以看到您的进程仍在屏幕上运行。要退出屏幕,输入#exit。

更多细节见man screen

在基于debian的系统上(在远程机器上) 安装:< / p >

Sudo apt-get install tmux

用法:

tmux

运行您想要的命令

重命名会话:

Ctrl + B然后

集名称

退出会话:

Ctrl + B然后D

(这会留下tmux会话)。此时可以退出SSH。

当您需要再次返回/检查它时,启动SSH,并输入

Tmux附加session_name

它将带您回到tmux会话。

我使用屏幕命令。这个链接详细说明了如何做到这一点

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

对于大多数进程,您可以使用这个旧的Linux命令行技巧进行伪守护:

# ((mycommand &)&)

例如:

# ((sleep 30 &)&)
# exit

然后启动一个新的终端窗口,然后:

# ps aux | grep sleep

将显示sleep 30仍在运行。

你所做的就是将该进程作为子进程的子进程启动,当你退出时,通常会触发该进程退出的nohup命令不会级联到子进程,使其成为一个孤儿进程,仍在运行。

我更喜欢这种“设置它并忘记它”的方法,不需要处理nohupscreen, tmux, I/o重定向,或任何类似的东西。

接受的答案建议使用nohup。我宁愿建议使用pm2。使用pm2而不是nohup有很多优点,比如保持应用程序的活动,维护应用程序的日志文件和许多其他特性。更多详细信息看看这个

要安装pm2,需要下载npm。基于Debian的系统

sudo apt-get install npm

还有红帽公司

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

使用应用程序名称或进程id管理进程或同时管理所有进程:

$ 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

在systemd/Linux上,systemd-run是一个很好的启动会话无关进程的工具。