【问题标题】:How to send a subprocess to the background & without using shell=True如何在不使用 shell=True 的情况下将子进程发送到后台
【发布时间】:2012-09-02 17:31:23
【问题描述】:

我正在尝试编写 Python 脚本的一部分,该脚本会在 Linux 下为小型 Web 管理界面更改根 MySQL 密码。我已经按照 MySQL 官方文档更改了 root 密码,并提出了这个 shell 脚本,效果很好:

shopt -s xpg_echo
# stopping running MySQL server
invoke-rc.d mysql stop

# creating init file in a mysqld readable location
cat > /var/lib/mysql/mysql-init <<END
UPDATE mysql.user SET Password=PASSWORD('x123') WHERE User='root';
FLUSH PRIVILEGES;
END

# running mysqld_safe with init-file in the background
mysqld_safe --init-file=/var/lib/mysql/mysql-init &

sleep 5

# stopping mysql
invoke-rc.d mysql stop

# deleting the init file
rm /var/lib/mysql/mysql-init

# starting mysql
invoke-rc.d mysql start

有一个部分,我必须启动 mysqld_safe 并让它运行几秒钟,然后用 invoke-rc.d 很好地停止它。在 shell 脚本中,我可以使用 &amp;sleep 5 来解决它。

我的问题是我不知道如何在 Python 脚本中执行此操作不使用 shell=True。我可以使用 Popen 和 shlex.split(cmd) 完成所有其他部分,但是 & 似乎既没有通过 shlex.split(cmd) 也没有通过 shell=False。

这只是命令行中&amp; 的一个简单问题,还是我真的需要 shell=True 来解决这个问题?如果没有,我需要使用线程吗?

【问题讨论】:

  • &amp; 由 shell 解释,因此您必须使用具有该语法的 shell。但是,您可以在 Python 中复制该功能,方法是使用系统调用 forkexec*setsid
  • 好的,我得到了外壳部分。但是不能把 Popen 放在一个线程中吗?
  • 是的,您也可以使用线程。这取决于您所说的“背景”到底是什么意思。要生成一个完全分离的子进程,您需要使用这些系统调用(以及其他),但对于一个短暂的进程,线程应该没问题。
  • 我想要做的只是等待大约 5 秒,而进程初始化,然后调用 invoke-rc.d mysql stop 停止它。背景只是一个想法,在 bash 脚本中运行良好。
  • 顺便说一句,仔细看,你怎么知道mysql_safe进程完成了?你怎么知道它成功退出了?既然你的脚本在睡眠时阻塞,为什么你不能等待它呢?

标签: python multithreading shell process subprocess


【解决方案1】:

我可能遗漏了一些东西,但这样的东西不会起作用吗?

import time
import subprocess

p = subprocess.Popen(['mysqld_safe', '--init-file=/var/lib/mysql/mysql-init'])
time.sleep(5)
subprocess.call(['invoke-rc.d', 'mysql', 'stop'])

【讨论】:

  • mysqld_safe 一直在前台运行,所以 Python 卡在这个命令上。这就是为什么我想使用线程,但 shell 更容易。
  • 有趣——我认为 Popen 不会发生这种情况。对于我尝试过的每个命令或脚本,Popen() 都会立即返回,并且它启动的进程会继续运行。
  • @zsero:Popen 立即返回。如果您的意思是python进程在执行完所有代码后继续运行;可能是another issue
【解决方案2】:

&amp; 是一个 shell 的东西,所以,是的,如果你想使用 &amp; 在后台运行命令,你需要 shell。但是,您也可以完全在 Python 中执行此操作:

proc = subprocess.Popen(["mysqld_safe", "--init-file=/var/lib/mysql/mysql-init"])
time.sleep(5)
proc.kill()

【讨论】:

    猜你喜欢
    • 2015-05-07
    • 2012-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-26
    相关资源
    最近更新 更多