为什么命令及其参数必须在子进程列表中。Popen?

问题描述 投票:0回答:2

我尝试做

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]
python linux subprocess
2个回答
0
投票

根据docs,它取决于shell=关键字参数关于字符串与列表的工作方式(粗体表示可能导致您经历的行为的原因:]

args应该是程序参数的序列,或者是单个字符串或类似路径的对象。默认情况下,如果args是序列,则要执行的程序是args中的第一项。如果args是字符串,则解释取决于平台,并在下面进行描述。有关默认行为的其他区别,请参见shell和可执行参数。除非另有说明,否则建议将args作为序列传递。

在POSIX上,如果args是字符串,则该字符串将解释为要执行的程序的名称或路径。但是,只有在不将参数传递给程序的情况下才能执行此操作。

进一步向下...

在具有shell = True的POSIX上,shell默认为/ bin / sh。如果args是字符串,则该字符串指定要通过外壳执行的命令。这意味着字符串的格式必须与在shell提示符下键入时的格式完全相同。例如,这包括在文件名中使用引号或反斜杠转义。如果args是序列,则第一项指定命令字符串,任何其他项都将被视为shell本身的其他参数。也就是说,Popen等效于:

Popen(['/bin/sh', '-c', args[0], args[1], ...])

在具有shell = True的Windows上,COMSPEC环境变量指定默认的shell。在Windows上唯一需要指定shell = True的时间是将要执行的命令内置到shell中(例如dir或copy)。您不需要shell = True即可运行批处理文件或基于控制台的可执行文件。


0
投票

这就是all进程调用在UNIX上的工作方式。

幕后,通常在UNIX上运行程序要执行以下步骤:

  1. fork()关闭子进程。
  2. 在该子进程中,如果需要重定向,请打开stdin,stdout,stderr等的新副本。
  3. 在该子进程中,使用execve() syscall将当前进程替换为所需的子进程。 此系统调用采用参数数组,而不是单个字符串。
  4. wait(),让孩子退出,如果要阻止该电话。

因此,subprocess.Popen公开了数组接口,因为数组接口是操作系统实际上在后台执行的操作

在外壳上运行ls /tmp时,该外壳将字符串转换为数组-但可以提供更多控制权(避免严重的错误-如果有人创建名为/tmp/$(rm -rf ~)的文件,您不想在自己进行转换时尝试cat /tmp/$(rm -rf ~)删除您的主目录。

© www.soinside.com 2019 - 2024. All rights reserved.