使用子进程在 Windows 上运行 Python 脚本
Posted
技术标签:
【中文标题】使用子进程在 Windows 上运行 Python 脚本【英文标题】:Using subprocess to run Python script on Windows 【发布时间】:2010-10-29 02:37:21 【问题描述】:有没有在 Windows/Linux/OS X 上运行 Python 脚本的简单方法?
在后两者上,subprocess.Popen("/the/script.py")
有效,但在 Windows 上出现以下错误:
Traceback (most recent call last):
File "test_functional.py", line 91, in test_functional
log = tvnamerifiy(tmp)
File "test_functional.py", line 49, in tvnamerifiy
stdout = PIPE
File "C:\Python26\lib\subprocess.py", line 595, in __init__
errread, errwrite)
File "C:\Python26\lib\subprocess.py", line 804, in _execute_child
startupinfo)
WindowsError: [Error 193] %1 is not a valid Win32 application
monkut'scomment:用例不清楚。为什么要使用 subprocess 来运行 python 脚本?是否有什么东西阻止您导入脚本并调用必要的函数?
我正在编写一个快速脚本来测试 Python 命令行工具的整体功能(在各种平台上进行测试)。基本上它必须在一个临时文件夹中创建一堆文件,在这个文件夹上运行脚本并检查文件是否正确重命名。
我本可以导入脚本并调用函数,但由于它依赖于sys.argv
并使用sys.exit()
,我需要执行类似的操作..
import sys
import tvnamer
sys.argv.append("-b", "/the/folder")
try:
tvnamer.main()
except BaseException, errormsg:
print type(errormsg)
另外,我想捕获 stdout 和 stderr 以便在出现问题时进行调试。
当然,更好的方法是以更可单元测试的方式编写脚本,但脚本基本上“完成”了,我正在做最后一批测试,然后再发布“1.0”版本(之后我'将进行重写/重组,这将更整洁,更可测试)
基本上,在找到sys.executable
变量后,将脚本作为进程简单地运行要容易得多。我会把它写成一个 shell 脚本,但这不会是跨平台的。最终脚本可以找到here
【问题讨论】:
用例不清楚。为什么要使用 subprocess 来运行 python 脚本?是否有什么东西阻止您导入脚本并调用必要的函数? 从 python 运行 nodejs 模块时遇到了同样的问题。 subprocess.call([r'..\nodejs\npm'], shell=True) 解决了这个问题。 【参考方案1】:补充信息:值得注意的是,如果您使用像 dir
这样的 dos shell 命令,则需要使用文档说明您需要使用 shell=True
没有它你会得到这样的结果。
>>> import subprocess
>>> subprocess.run(['dir'])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\foo\AppData\Local\Programs\Python\Python38\lib\subprocess.py", line 489, in run
with Popen(*popenargs, **kwargs) as process:
File "C:\Users\foo\AppData\Local\Programs\Python\Python38\lib\subprocess.py", line 854, in __ini
t__
self._execute_child(args, executable, preexec_fn, close_fds,
File "C:\Users\foo\AppData\Local\Programs\Python\Python38\lib\subprocess.py", line 1307, in _exe
cute_child
hp, ht, pid, tid = _winapi.CreateProcess(executable, args,
FileNotFoundError: [WinError 2] The system cannot find the file specified
>>> subprocess.run(['dir'], shell=True)
Volume in drive J is garbage
Volume Serial Number is 5EE7-B084
您还可以对最近添加的 args 使用类似路径的对象。
from pathlib import Path
subprocess.run(Path('c:/proj/myfile.bat'))
另外值得注意的是,有一整套windows specific controls 允许您控制进程的生成方式,哪些并发操作可以使用。
所以在windows上控制子进程并不像posix风格那么简单。
【讨论】:
【参考方案2】:刚刚找到sys.executable
——当前 Python 可执行文件的完整路径,可用于运行脚本(而不是依赖 shbang,这显然不适用于 Windows)
import sys
import subprocess
theproc = subprocess.Popen([sys.executable, "myscript.py"])
theproc.communicate()
【讨论】:
你可以改用subprocess.check_call([sys.executable, "myscript.py"])
。
或者更好的是,在 Python 3.5+ 中,使用 subprocess.run
: subprocess.run([sys.executable, 'myscript.py'], check=True)
【参考方案3】:
例如,要使用命令提示符或 BATCH 文件执行以下操作,我们可以使用:
C:\Python27\python.exe "C:\Program files(x86)\dev_appserver.py" --host 0.0.0.0 --post 8080 "C:\blabla\"
与 Python 一样,我们可以这样做:
subprocess.Popen(['C:/Python27/python.exe', 'C:\\Program files(x86)\\dev_appserver.py', '--host', '0.0.0.0', '--port', '8080', 'C:\\blabla'], shell=True)
或
subprocess.Popen(['C:/Python27/python.exe', 'C:/Program files(x86)/dev_appserver.py', '--host', '0.0.0.0', '--port', '8080', 'C:/blabla'], shell=True)
【讨论】:
【参考方案4】:是的subprocess.Popen(cmd, ..., shell=True)
就像一个魅力。在 Windows 上,.py
文件扩展名被识别,因此调用 Python 来处理它(在 *NIX 上只是通常的 shebang)。路径环境控制事物是否被看到。所以Popen
的第一个参数是只是脚本的名称。
subprocess.Popen(['myscript.py', 'arg1', ...], ..., shell=True)
【讨论】:
shell=True # do not show the command prompt then true, if false show it
【参考方案5】:
这个怎么样:
import sys
import subprocess
theproc = subprocess.Popen("myscript.py", shell = True)
theproc.communicate() # ^^^^^^^^^^^^
这告诉subprocess
使用操作系统外壳打开您的脚本,并处理您可以在 cmd.exe 中运行的任何内容。
此外,这将在 PATH 中搜索“myscript.py” - 这可能是可取的。
【讨论】:
我认为它的功能是一样的,如果我记得正确的 shell=True 只是阻止子进程转义任何特殊字符(所以“mycmd > somefile.txt”将文本重定向到 somefile.txt,而不是试图执行一个名为“mycmd > somefile.txt”的文件) 这里是两者明显不同的情况。假设“myscript.py”在系统 PATH 中,而不是在当前目录中。如果您使用“shell = True”,脚本将在 PATH 中找到,但如果您使用“sys.executable”,则不会。 啊,我明白你的意思了(尽管我试图运行的脚本总是在当前目录中) 修复了我的错误,顺便说一下,它在 python3 上没有 shell = True 并且在 2.7 上失败,不知道为什么。【参考方案6】:您正在使用依赖于平台的路径名分隔符。 Windows 使用“\”,Unix 使用“/”。
【讨论】:
好点,虽然在导致错误的实际脚本中我使用了 os.path.join() (虽然我应该提到这一点) 当然,正斜杠从史前时代就在 Windows 上有效,现在仍然有效,所以这不是问题。 @romkyns 不是真的: subprocess.call([r'..\nodejs\npm'], shell=True) 有效,而 subprocess.call(['../nodejs/npm'] , shell=True) 给出 '..' 不被识别为内部或外部命令 @Stefan,这将是 shell 的抱怨,而不是底层的 Windows API。【参考方案7】:看起来 windows 尝试使用自己的 EXE 框架运行脚本,而不是像这样调用它
python /the/script.py
试试,
subprocess.Popen(["python", "/the/script.py"])
编辑:“python”需要在你的路径上。
【讨论】:
python.org Windows 安装程序似乎没有将“python”命令放在 PATH 中,我认为它会有 .exe 后缀(这会破坏其他平台) 嗯,Windows 上的 .exe 好像只要在 PATH 中就可以排除,但要手动添加 Python 所以使用“cmd /S /C”而不是“python”——它总是在路径上,只要扩展注册了就会运行脚本。【参考方案8】:当您在子进程中的 windows 上运行 python 脚本时,您应该在脚本名称前使用 python。试试:
process = subprocess.Popen("python /the/script.py")
【讨论】:
以上是关于使用子进程在 Windows 上运行 Python 脚本的主要内容,如果未能解决你的问题,请参考以下文章
在 Windows 上将 ^C 发送到 Python 子进程对象
使用 python 子进程检查 pip 是不是安装在 Windows 上
在 Windows 上使用 bq load 和 python 子进程分隔的加载管道