如何在退出SSH后仍然在后台运行脚本?

160

我有一个名为bgservice.py的Python脚本,它是我构建的web服务的一部分。 我想要它始终运行,即使在注销SSH之后也是如此。我该怎么做?

12个回答

277

运行nohup python bgservice.py &可以使脚本忽略挂起信号并继续运行。输出将被放置在nohup.out中。

理想情况下,您应该像使用supervise一样运行您的脚本,这样如果(当)脚本死亡,它可以被重新启动。


22
当我使用nohup和&运行命令时,我收到消息:nohup: ignoring input and appending output to nohup.out'`,并且当我按回车键时,该进程以状态1退出。出了什么问题? - Santosh Ghimire
2
请阅读 nohup.out 的输出。在我的情况下,这是一个权限问题,我需要使用 sudo。 - mxns
2
如何在此方法运行后停止bgservice? - fire in the hole
1
@Shaegorath 在某个地方保存pid,以便稍后可以向该进程发送信号。在某些shell(如bash、zsh等)中,在执行somecommand &之后,它会打印pid,例如[1] 12345。否则,您可以使用$! - Tony Beta Lambda
1
我一直在研究nohup作为解决这个问题的推荐方案,但我发现输出文件nohup.out是在Python脚本结束后生成的。它不允许您在Python脚本运行时追加结果。我也不知道如何使用nohup提供脚本输入。我没有测试线程的行为,但出于以上原因,这对我来说不是一个好的解决方案。所以我会继续寻找其他解决方案或建议。我希望可以在使用ssh登录时与我的应用程序进行交互。 - Sodanetworks

42
如果您已经开始了该进程,而不想在nohup下终止它并重新启动,则可以将其发送到后台,然后使其脱离控制。

Ctrl+Z(暂停该进程)

bg(在后台重新启动该进程)

disown %1(假设这是作业#1,请使用jobs来确定)


我该如何让它停止向标准输出打印? - Hairy

33

在后台运行Python脚本

首先,您需要在Python脚本中添加shebang行,它看起来像下面这样:

#!/usr/bin/env python3

如果您安装了多个版本的Python,则需要此路径,并且/usr/bin/env将确保使用您$$PATH环境变量中的第一个Python解释器。您也可以硬编码您的Python解释器路径(例如#!/usr/bin/python3),但这不够灵活,也不便于在其他计算机上移植。接下来,您需要设置文件权限以允许执行:

chmod +x test.py

现在你可以使用nohup运行脚本,它会忽略挂起信号。这意味着你可以关闭终端而不停止执行。另外,别忘了添加&使得脚本在后台运行:
nohup /path/to/test.py &

如果您没有在文件中添加{{shebang}},则可以使用以下命令运行脚本:
nohup python /path/to/test.py &

输出结果将保存在nohup.out文件中,除非您像这样指定输出文件:
nohup /path/to/test.py > output.log &
nohup python /path/to/test.py > output.log &

如果您将命令的输出重定向到其他位置,包括 /dev/null,那么输出会发送到指定位置。
# doesn't create nohup.out

nohup command >/dev/null 2>&1   

如果你正在使用nohup,那可能意味着你想通过在整个命令结尾添加另一个&来将命令在后台运行:

# runs in background, still doesn't create nohup.out

 nohup command >/dev/null 2>&1 &  

你可以使用以下命令找到 进程 及其 进程 ID

ps ax | grep test.py

# or
# list of running processes Python

ps -fA | grep python

ps代表进程状态。

如果你想停止执行,可以使用kill命令kill它:

kill PID

如果我想在退出SSH之前仍然从SSH终端接受标准输入,该怎么办? - Luk Aron
这个话题是关于背景而不是标准执行的。不管怎样,我认为你的答案在这个优秀的文档中。 - Milovan Tomašević
1
这是一个非常好的、非常完整的回答。谢谢@MilovanTomašević。 - undefined

17

你也可以使用GNU screen,几乎所有的Linux/Unix系统都应该有它。

如果你在Ubuntu/Debian上,它的增强版byobu也很不错。


15

备选答案:tmux

  • ssh到远程机器
  • 在cmd中输入tmux
  • tmux中启动您想要的进程,例如python3 main.py
  • 通过Ctrl+b然后d离开tmux会话

现在安全退出远程计算机。当您回来时,使用tmux attach重新进入tmux会话。

如果您想启动多个会话,请使用Ctrl+b然后$为每个会话命名。然后输入您的会话名称。

要列出所有会话,请使用tmux list-sessions

要附加运行会话,请使用tmux attach-session -t <session-name>


15
你可以考虑将你的 Python 脚本转化为一个正式的 Python 守护进程。具体操作可以参考这里python-daemon 是一个好工具,可以将 Python 脚本作为后台守护进程运行,而不是一直运行的脚本。你需要稍微修改现有代码,但很简单易懂。
如果你在使用 python-daemon 时遇到问题,还有另外一个实用工具supervisor,可以用来将进程变成守护进程,此时你就无需编写任何代码(或者修改现有代码),因为它是一个开箱即用的解决方案。

1
通常提供关于如何解决问题的简要说明是一个好主意。 - Nikhil Sahu

8

你可以使用 nohup,但我更喜欢使用 screen


6

以下是使用装饰器在Python中的简单解决方案:

import os, time

def daemon(func):
    def wrapper(*args, **kwargs):
        if os.fork(): return
        func(*args, **kwargs)
        os._exit(os.EX_OK)
    return wrapper

@daemon
def my_func(count=10):    
  for i in range(0,count):
     print('parent pid: %d' % os.getppid())
     time.sleep(1)


my_func(count=10)
#still in parent thread
time.sleep(2)
#after 2 seconds the function my_func lives on is own

当然,你可以用你的代码替换bgservice.py文件中的内容来代替my_func


2
也许需要捕获SIGHUP信号。然后在您的代码块中添加signal.signal(signal.SIGHUP, handler)。 - Chouettou
是的,这里似乎不起作用。当父进程退出时,子进程也会终止。 - olejorgenb

5

试试这个:

nohup python -u <your file name>.py >> <your log file>.log &

您可以在screen中运行上述命令并退出screen。

现在,您可以通过以下方式跟踪Python脚本的日志:tail -f <your log file>.log

要终止脚本,您可以使用ps -auxkill命令。


如果我想在退出ssh之前仍然从ssh终端接受标准输入,怎么办? - Luk Aron

3

zsh shell有一个选项,可以使所有后台进程都使用nohup运行。

~/.zshrc文件中添加以下行:

setopt nocheckjobs  #don't warn about bg processes on exit
setopt nohup        #don't kill bg processes on exit

然后,您只需要运行以下进程:python bgservice.py &,您将不再需要使用nohup命令。

我知道并不是很多人使用zsh,但它是一个非常酷的shell,我强烈推荐使用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接