298

我正在通过 SSH (Putty) 在 Linux 机器上工作。我需要让一个进程在夜间运行,所以我想我可以通过在后台启动进程(在命令末尾带有一个&符号)并将标准输出重定向到一个文件来做到这一点。

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

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

4

20 回答 20

309

查看“ nohup ”程序。

于 2008-11-12T19:21:30.157 回答
169

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

于 2008-11-12T19:22:00.313 回答
82

当会话关闭时,进程接收到它显然没有捕获的 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.
于 2008-11-12T19:27:26.307 回答
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

你去那里,产生任何东西。<(:) 通过进程替换打开一个匿名管道,该管道死了,但管道仍然存在,因为你有它的句柄。我通常会做 asleep 1而不是:因为它有点活泼,而且我会得到一个“文件忙”错误——如果运行真正的命令(例如,command true)永远不会发生

“heredoc 采购”:

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

这适用于我尝试过的每一个 shell,包括busybox/etc(initramfs)。我以前从未见过它,我在刺激时独立发现它,谁知道source可以接受args?但如果有这样的事情,它通常作为一种更易于管理的 eval 形式。

于 2012-03-10T12:01:44.263 回答
37
nohup blah &

将您的进程名称替换为 blah!

于 2008-11-12T19:31:35.660 回答
17

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

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

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

于 2008-11-12T19:53:57.970 回答
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)。由于双破折号在任何地方都可以使用,因此最好使用它。

如果您想要daemonize.

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

于 2008-11-12T19:50:05.233 回答
10

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

# ((mycommand &)&)

例如:

# ((sleep 30 &)&)
# exit

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

# ps aux | grep sleep

将显示sleep 30仍在运行。

您所做的是将进程作为子进程启动,当您退出时,nohup通常会触发进程退出的命令不会级联到孙子进程,使其成为孤立进程,仍在运行.

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

于 2016-07-03T00:59:11.907 回答
7

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

sudo apt-get install tmux

用法:

多路复用器

运行你想要的命令

重命名会话:

Ctrl+B然后$

设置名称

退出会话:

Ctrl+B然后D

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

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

tmux 附加会话名称

它将带您回到您的 tmux 会话。

于 2014-04-25T23:30:46.767 回答
5

如果父进程被杀死,Nohup 允许客户端进程不被杀死,作为您注销时的参数。更好的是仍然使用:

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

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

于 2008-11-12T19:35:15.747 回答
5

如果您使用 screen 以 root 身份运行进程,请注意特权提升攻击的可能性。如果您自己的帐户以某种方式受到损害,将有一种直接的方式来接管整个服务器。

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

于 2008-11-12T19:53:08.580 回答
5

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

你需要知道的基本命令:

开始画面

屏幕


创建下一个屏幕

ctrl+a+c


移动到创建的下一个屏幕

ctrl+a+n


分离_ _

ctrl+a+d


在工作期间关闭你的腻子。下次您通过腻子类型登录时

屏幕-r

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

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

于 2014-03-05T05:28:07.583 回答
3

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

于 2008-11-12T19:23:01.700 回答
2

如果您也愿意运行 X 应用程序 - 将xpra与“screen”一起使用。

于 2011-11-15T00:17:53.500 回答
2

我也会选择屏幕程序(我知道其他人的答案是屏幕,但这是一个完成)

不仅 &、ctrl+z bg disown、nohup 等可能会给你一个令人讨厌的惊喜,即当你注销工作时仍然会被杀死(我不知道为什么,但它确实发生在我身上,而且它没有打扰因为我切换到使用屏幕,但我猜 anthonyrisinger 解决方案,因为双分叉可以解决这个问题),屏幕也比仅仅背景有一个主要优势:

screen will background your process without losing interactive control to it

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

于 2012-05-30T09:23:05.840 回答
2

还有开源 libslack 包的daemon命令。

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

于 2012-06-16T16:13:26.003 回答
2

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

$ ssh myhost 'sleep 30 >&- 2>&- <&- &'
# ssh returns right away, and your sleep job is running remotely
$
于 2013-08-14T15:51:50.590 回答
1

我使用了屏幕命令。此链接详细介绍了如何执行此操作

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

于 2015-11-12T05:02:58.567 回答
1

接受的答案建议使用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 运行。您必须对 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
于 2017-02-06T08:59:04.860 回答
0

在 systemd/Linux 上,systemd-run是启动独立于会话的进程的好工具。

于 2017-12-26T17:10:28.490 回答