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

2024-04-26 14:10:20 发布

您现在位置:Python中文网/ 问答频道 /正文

我试过了

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]

Tags: noimportreadstderrstdoutetclsla
2条回答

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

args should be a sequence of program arguments or else a single string or path-like object. By default, the program to execute is the first item in args if args is a sequence. If args is a string, the interpretation is platform-dependent and described below. See the shell and executable arguments for additional differences from the default behavior. Unless otherwise stated, it is recommended to pass args as a sequence.

On POSIX, if args is a string, the string is interpreted as the name or path of the program to execute. However, this can only be done if not passing arguments to the program.

再往下。。。你知道吗

On POSIX with shell=True, the shell defaults to /bin/sh. If args is a string, the string specifies the command to execute through the shell. This means that the string must be formatted exactly as it would be when typed at the shell prompt. This includes, for example, quoting or backslash escaping filenames with spaces in them. If args is a sequence, the first item specifies the command string, and any additional items will be treated as additional arguments to the shell itself. That is to say, Popen does the equivalent of:

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

On Windows with shell=True, the COMSPEC environment variable specifies the default shell. The only time you need to specify shell=True on Windows is when the command you wish to execute is built into the shell (e.g. dir or copy). You do not need shell=True to run a batch file or console-based executable.

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

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

  1. ^{}关闭子进程。你知道吗
  2. 在该子进程中,如果请求重定向,则打开stdin、stdout、stderr等的新副本,使用^{}调用将新打开的文件分配给作为重定向目标的文件描述符。你知道吗
  3. 在该子进程中,使用^{}系统调用将当前进程替换为所需的子进程。此系统调用采用参数数组,而不是单个字符串。
  4. ^{}如果要阻止调用,则子进程退出。你知道吗

因此,subprocess.Popen公开了数组接口,因为数组接口是操作系统在引擎盖下实际执行的操作。你知道吗

当您在shell上运行ls /tmp时,该shell会将字符串转换为一个数组,然后自己执行上面的步骤,但它会为您提供更多的控制(如果有人创建名为/tmp/$(rm -rf ~)的文件,您不希望尝试cat /tmp/$(rm -rf ~)删除主目录),而您自己执行转换时,它会避免出现严重的错误。你知道吗

相关问题 更多 >