我试过
import subprocess
p = subprocess.Popen("ls -la /etc", stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p.stdout.read().decode()
这给了我
FileNotFoundError: [Errno 2] No such file or directory: 'ls -la /etc': 'ls -la /etc'
关注
Python subprocess.Popen with var/args
我做到了
import subprocess
p = subprocess.Popen(["ls", "-la", "/etc"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p.stdout.read().decode()
哪个有效。
这是为什么呢?为什么我必须拆分我的命令及其参数?这种设计背后的基本原理是什么?
Python 版本:
3.7.3 (default, Mar 27 2019, 22:11:17)
[GCC 7.3.0]
最佳答案
这就是所有进程调用在 UNIX 上的工作方式。
在幕后,在 UNIX 上运行程序传统上是通过以下步骤完成的:
-
fork()
关闭子进程。 - 在该子进程中,如果请求重定向,则打开 stdin、stdout、stderr 等的新副本,使用
dup2()
调用以将新打开的文件分配给作为重定向目标的文件描述符。 - 在该子进程中,使用
execve()
系统调用以用所需的子进程替换当前进程。 此系统调用采用参数数组,而不是单个字符串。 -
wait()
如果调用是阻塞的,则让 child 退出。
因此,subprocess.Popen
公开了数组接口(interface),因为数组接口(interface)是操作系统在幕后实际执行的操作。
当您在 shell 中运行 ls/tmp
时,那个 shell 会将字符串转换为一个数组,然后自行执行上述步骤——但它给了您更多的控制权(并避免严重的错误——如果有人创建了一个名为 /tmp/$(rm -rf ~)
的文件,你不想尝试 cat/tmp/$(rm -rf ~)
在您自己进行转换时删除您的主目录。
关于python - 为什么命令及其参数必须在 subprocess.Popen 的列表中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58440143/