简体   繁体   English

如何从Python脚本在后台执行Shell脚本

[英]How to execute a shell script in the background from a Python script

I am working on executing the shell script from Python and so far it is working fine. 我正在从Python执行Shell脚本,到目前为止,它工作正常。 But I am stuck on one thing. 但是我坚持一件事。

In my Unix machine I am executing one command in the background by using & like this. 在我的Unix机器上,我使用&这样在后台执行一个命令。 This command will start my app server - 此命令将启动我的应用服务器-

david@machineA:/opt/kml$ /opt/kml/bin/kml_http --config=/opt/kml/config/httpd.conf.dev &

Now I need to execute the same thing from my Python script but as soon as it execute my command it never goes to else block and never prints out execute_steps::Successful , it just hangs over there. 现在,我需要从Python脚本中执行相同的操作,但是一旦它执行了我的命令,它就永远不会转到else block ,也永远不会打印出execute_steps::Successful ,它只是挂在那上面。

proc = subprocess.Popen("/opt/kml/bin/kml_http --config=/opt/kml/config/httpd.conf.dev &", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, executable='/bin/bash')
if proc.returncode != 0:
    logger.error("execute_steps::Errors while executing the shell script: %s" % stderr)
    sleep(0.05) # delay for 50 ms
else:
    logger.info("execute_steps::Successful: %s" % stdout)

Anything wrong I am doing here? 我在这里做错什么了吗? I want to print out execute_steps::Successful after executing the shell script in the background. 我想在后台执行shell脚本后打印出execute_steps::Successful

All other command works fine but only the command which I am trying to run in background doesn't work fine. 所有其他命令都可以正常运行,但是只有我要在后台运行的命令无法正常运行。

There's a couple things going on here. 这里发生了几件事。

First, you're launching a shell in the background, and then telling that shell to run the program in the background. 首先,您要在后台启动Shell,然后告诉该Shell在后台运行程序。 I don't know why you think you need both, but let's ignore that for now. 我不知道您为什么认为两者都需要,但现在让我们忽略它。 In fact, by adding executable='/bin/bash' on top of shell=True , you're actually trying to run a shell to run a shell to run the program in the background, although that doesn't actually quite work.* 实际上,通过在shell=True顶部添加executable='/bin/bash' ,您实际上是在尝试运行一个Shell来运行一个Shell来在后台运行程序,尽管实际上并没有什么用。 *

Second, you're using PIPE for the process's output and error, but then not reading them. 其次,您将PIPE用于过程的输出和错误,但不读取它们。 This can cause the child to deadlock. 这可能导致孩子陷入僵局。 If you don't want the output, use DEVNULL , not PIPE . 如果您不想要输出,请使用DEVNULL ,而不要使用PIPE If you want the output to process yourself, use proc.communicate() .**, or use a higher-level function like check_output . 如果您希望输出proc.communicate()处理,请使用proc.communicate() 。**,或使用诸如check_output的更高级别的函数。 If you just want it to intermingle with your own output, just leave those arguments off. 如果只希望它与您自己的输出混合在一起,则只需取消这些参数即可。

* If you're using the shell because kml_http is a non-executable script that has to be run by /bin/bash , then don't use shell=True for that, or executable , just make make /bin/bash the first argument in the command line, and /opt/kml/bin/kml_http the second. *如果您使用shell是因为kml_http是必须由/bin/bash运行的不可执行脚本,则不要为此使用shell=Trueexecutable ,只需将/bin/bash第一个命令行中的参数,第二个是/opt/kml/bin/kml_http But this doesn't seem likely; 但这似乎不太可能。 why would you install something non-executable into a bin directory? 为什么要在bin目录中安装不可执行的内容?

** Or you can read it explicitly from proc.stdout and proc.stderr , but that gets more complicated. **或者,您可以从proc.stdoutproc.stderr显式读取它,但这变得更加复杂。


At any rate, the whole point of executing something in the background is that it keeps running in the background, and your script keeps running in the foreground. 无论如何,在后台执行某件事的全部意义在于它始终在后台运行,而脚本始终在前台运行。 So, you're checking its returncode before it's finished, and then moving on to whatever's next in your code, and never coming back again. 因此,您需要在returncode代码完成之前检查其returncode代码,然后继续执行代码中的下一个操作,而再也不会返回。


It seems like you want to wait for it to be finished. 似乎您要等待其完成。 In that case, don't run it in the background—use proc.wait , or just use subprocess.call() instead of creating a Popen object. 在这种情况下,请勿在后台运行它-使用proc.wait ,或仅使用proc.wait subprocess.call()而不是创建Popen对象。 And don't use & either, of course. 当然,也不要使用& While we're at it, don't use the shell, either: 当我们使用它时,请不要使用外壳程序:

retcode = subprocess.call(["/opt/kml/bin/kml_http",
                           "--config=/opt/kml/config/httpd.conf.dev"],
                          stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
if retcode != 0:
    # etc.

Now, you won't get to that if statement until kml_http finishes running. 现在,在kml_http完成运行之前,您将无法使用if语句。


If you want to wait for it to be finished, but at the same time keep doing other stuff, then you're trying to do two things at once in your program, which means you need a thread to do the waiting: 如果您想等待它完成,但同时又继续做其他事情,那么您将尝试在程序中一次完成两件事,这意味着您需要一个线程来进行等待:

def run_kml_http():
    retcode = subprocess.call(["/opt/kml/bin/kml_http",
                               "--config=/opt/kml/config/httpd.conf.dev"],
                              stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    if retcode != 0:
        # etc.

t = threading.Thread(target=run_kml_http)
t.start()
# Now you can do other stuff in the main thread, and the background thread will
# wait around until kml_http is finished and execute the `if` statement whenever
# that happens

You're using stderr=PIPE, stdout=PIPE which means that rather than letting the stdin and stdout of the child process be forwarded to the current process' standard output and error streams, they are being redirected to a pipe which you must read from in your python process (via proc.stdout and proc.stderr . 您使用的是stderr=PIPE, stdout=PIPE ,这意味着与其让子进程的stdinstdout转发到当前进程的标准输出和错误流,不如将它们重定向到必须从中读取的管道在您的python进程中(通过proc.stdoutproc.stderr

To "background" a process, simply omit the usage of PIPE : 要使过程“后台”,只需省略PIPE的用法即可:

#!/usr/bin/python
from subprocess import Popen
from time import sleep

proc = Popen(
    ['/bin/bash', '-c', 'for i in {0..10}; do echo "BASH: $i"; sleep 1; done'])

for x in range(10):
    print "PYTHON: {0}".format(x)
    sleep(1)

proc.wait()

which will show the process being "backgrounded".

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM