在Linux中关闭SSH客户端后如何防止后台进程停止


291

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

令我惊讶的是,这行不通。一旦我关闭“腻子”窗口,该过程就会停止。

如何防止这种情况发生?

Answers:


301

出“ nohup ”程序。


4
之后如何停止?
德里克·达默

9
登录并执行“ kill <pid>”。如果您不知道pid,请使用“ pidof”。
JesperE

32
您可以nohup command > /dev/null 2>&1 &用来在后台运行,而无需创建任何stdout或stderr输出(无nohup.out文件)
KCD 2013年

如果我需要提供一些信息怎么办?例如,我有一个需要长时间在后台运行的脚本,但该脚本首先要求输入我的FTP密码。nohup在这种情况下无济于事。有办法摆弄Ctrl+Z/ bg吗?
谢尔盖(Sergey)2013年

1
由于我懒惰并且不善于记住字符的神秘序列,因此我根据@KCD所说的内容编写了代码,并且已经使用了很多。
异常,

167

我建议使用GNU Screen。它允许您在所有进程继续运行时与服务器断开连接。在知道它存在之前,我不知道没有它我该如何生活。


7
这是我曾经使用过的最伟大的软件之一。说真的 我让它运行在我从任何地方都可以插入的BSD盒中,并且可以简单地重新连接到我的屏幕上,并使我的所有终端都在做各种各样的事情。
亚当·贾斯基维奇

1
我可以证明这一点。屏幕是一个很好的应用程序。重新连接的能力令人惊叹,并节省了大量可能丢失的工作。
willasaywhat

我什至在本地计算机上使用它,并将多个xterm附加到同一屏幕会话(screen -x)。这样,我可以在屏幕会话中打开许多窗口,并在窗口之间自由切换各种xterm。
亚当·贾斯基维奇

17
取决于您是否需要重新连接到后台应用程序。如果您这样做的话,是的,屏幕是唯一的飞行方式。但是,如果这是一劳永逸的做法,那么nohup甚至可以更好地满足要求。
戴夫·谢罗曼

1
屏幕+1。或者,作为替代,tmux(我比屏幕更喜欢这个)甚至byobu,这是screen或tmux的不错的前端。您可以键入screen以获取要使用的shell,并在以后随时返回,或者使用screen运行您的命令,例如“ screen command”:只要进程“ command”存在,screen会话就将存在。很长一段时间,您可以随时返回并查看其标准输出。
gerlos 2014年

81

当会话关闭时,该过程接收到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.

4
这样做的好处是可以取消已经启动的流程。
Christian K.

1
'jobspec'是指pid吗?
斯图尔特

1
不用担心,在这里找到这个答案stackoverflow.com/questions/625409/...
斯图尔特

42

守护吗?不行吗 屏幕?(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的,而不是:因为它稍微活泼,我会得到一个“文件忙”的错误-如果一个真正的命令是跑从未发生(如command true

“ heredoc采购”:

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

这适用于我尝试过的每个外壳程序,包括busybox / etc(initramfs)。我以前从未见过它,我在探测时独立地发现了它,谁知道源代码可以接受args?但是,如果存在这种情况,它通常可以作为一种更易于管理的评估形式。


2
为何要投反对票...那么,如果问题仍然存在,该怎么办?考虑到还有11个其他答案很显然很重要。在没有系统的情况下,此解决方案是惯用的,公认的方式来进行守护进程,而不是毫无意义的应用程序。Nohup等。
anthonyrisinger 2012年

7
无论您的回答有多好,有时SO上的某个人都会不喜欢它,并且会投反对票。最好不要担心太多。
Alex D

1
@ tbc0 ... tryssh myhost "((exec sleep 500)&) >/dev/null"
anthonyrisinger

1
@anthonyrisinger好的,可以。我认为这更干净:ssh myhost 'sleep 500 >&- 2>&- <&- &'
TMTOWTDI

1
这很棒。真正在busybox中有效的唯一解决方案。它值得更多投票
Hamy


17

就个人而言,我喜欢“批处理”命令。

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

这会将其填充到后台,然后将结果邮寄给您。这是cron的一部分。


11

正如其他人指出的那样,要在后台运行进程以便可以从SSH会话断开连接,您需要让后台进程正确地将其自身与其控制终端解除关联-这是SSH会话使用的伪tty。

您可以在诸如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          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)。由于双破折号在任何地方都可以使用,因此最好使用它。

如果您需要的来源,仍可以与我联系(gmail.com上的firstname dot lastname)daemonize

但是,代码是现在(终于)在我的GitHub上可用的SOQ(堆栈溢出问题)存储库中的文件daemonize-1.10.tgz 的子目录。


13
为什么不将源代码放在github或bitbucket上?
罗布

5
为什么缺少github上的源代码会导致失败?
乔纳森·莱夫勒

7
@JonathanLeffler恕我直言,列出了该程序的所有很酷的选择,这些程序没有以任何形式(甚至不是商业形式)公开提供,这浪费了读者的时间。
DepressedDaniel

7

在基于Debian的系统上(在远程计算机上)安装:

须藤apt-get install tmux

用法:

多路复用器

运行您想要的命令

重命名会话:

Ctrl + B然后$

设置名称

要退出会话:

按Ctrl + B,然后按D

(这将离开tmux会话)。然后,您可以注销SSH。

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

tmux附加session_name

它将带您回到tmux会话。


这就是要走的路
kilgoretrout

6

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

# ((mycommand &)&)

例如:

# ((sleep 30 &)&)
# exit

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

# ps aux | grep sleep

将显示sleep 30仍在运行。

您所做的是作为一个孩子的孩子启动该过程的,当您退出时,nohup通常会触发该过程退出的命令不会级联到孙子,而将其作为一个孤儿过程继续运行。

我更喜欢这个“设置它和忘记它”的方法,无需处理nohupscreen,TMUX,I / O重定向,或任何东西。


5

如果使用屏幕以超级用户身份运行进程,请注意特权提升攻击的可能性。如果您自己的帐户因某种原因受到侵害,将有直接方法来接管整个服务器。

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


5

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

您需要了解的基本命令:

开始画面

屏幕


为了ç reate下一屏

Ctrl + A + C


要移动到ñ分机屏幕创建

Ctrl + A + N


d etach

Ctrl + A + D


工作期间关闭油灰。下次当您通过腻子类型登录时

屏幕-r

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

有关更多详细信息,请参见man screen


如果yum您不了解发行版,那么假设这是正确的工具是不好的。您应该明确说明screen可以使用哪些发行版进行安装yum
tymik '16

5

如果注销父进程,则Nohup允许在父进程被杀死时不杀死客户机进程。更好的还是使用:

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

Nohup使您开始的进程不受终止的影响,该会话在注销后会终止您的SSH会话及其子进程。我提供的命令为您提供了一种将应用程序的pid存储在pid文件中的方式,以便您以后可以正确地将其杀死,并允许该过程在注销后运行。




2

我也会去看屏幕程序(我知道另外一个答案是屏幕,但这是一个完成)

不仅&&ctrl + z bg消失,nohup等事实可能会给您带来令人讨厌的惊喜,即您注销工作时仍然会被杀死(我不知道为什么,但这确实发生在我身上,并且没有引起您的注意)由于这是我切换为使用屏幕的原因,但是我猜想anthonyrisinger解决方案可以解决此问题,因为双重分叉可以解决该问题),相比于仅使用背景,屏幕也具有主要优势:

screen will background your process without losing interactive control to it

顺便说一句,这是我永远不会问的一个问题:) ...我从在任何unix中开始做任何事情就开始使用screen ...我(几乎)从不在unix / linux shell中工作而不启动screen首先...我现在应该停下来,否则我将无休止地介绍什么是好的屏幕,以及对您有什么帮助...亲自查找,值得;)


PS anthonyrisinger,你很好,我给你,但是... 30年?我敢打赌,当&,bg,nohup或screen还不存在时,这是一个解决方案,没有冒犯之处,我感谢您的知识,但是使用起来太复杂了:)
THESorcerer 2012年

2
(另外:请参阅Tmux),尽管这早于我[1987],但Thompson shell在1971年为UNIX 的第一个版本&引入了(异步执行)…… 所以它的字面意思是“一直”;-) las,我太保守了-实际上已经有41年了。
anthonyrisinger 2012年

2

还有开源libslack软件包的daemon命令。

daemon 是非常可配置的,并且确实关心所有繁琐的守护程序,例如自动重启,日志记录或pidfile处理。


2

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

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


1

接受的答案建议使用nohup。我宁愿建议使用pm2。在nohup上使用pm2具有许多优点,例如保持应用程序处于活动状态,维护应用程序的日志文件以及更多其他功能。有关更多详细信息,请查看

要安装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

使用应用程序名称或进程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运行。您必须对jason文件进行更改。将更"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

可以用来运行二进制可执行文件吗?
GetFree

@免费; 是。您可以。
鹰头鹰队'17

请添加示例。现在的答案似乎只对脚本文件有用。
GetFree

@免费; 添加了示例。如果您有任何问题,请告诉我。
鹰派'17

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.