subprocess.Popen 如何在 Windows 上与 shell=False 一起使用?

2024-01-16

我想了解如何子进程.Popen https://docs.python.org/3/library/subprocess.html#subprocess.Popen在 Windows 上工作时shell=False。特别是,底层算法如何考虑环境或变量扩展?

考虑下面的简单测试:

import os
import subprocess
import textwrap


def truncate(string, width):
    if len(string) > width:
        string = string[:width - 3] + '...'
    return string


if __name__ == '__main__':
    index = 0
    commands = [
        ["where", "find.exe"],
        "where find.exe",

        [r"c:\windows\system32\where.exe", "find.exe"],
        r"c:\windows\system32\where.exe find.exe",

        ["find.exe", "--version"],
        "find.exe --version",

        r"D:\sources\personal\sublimemerge\Git\usr\bin\find.exe --version",
    ]

    def run(target, shell):
        global index
        label = (
            f'{index:<2}) subprocess.run('
            f'{repr(target)}, shell={shell}, '
            f'stdout=subprocess.PIPE, stderr=subprocess.STDOUT, '
            f'universal_newlines=True)'
        )
        label = f"{label:<160}"

        try:
            x = subprocess.run(target, shell=shell, stdout=subprocess.PIPE,
                               stderr=subprocess.STDOUT, universal_newlines=True)
            print(f"{label} - returncode={x.returncode} - {repr(truncate(x.stdout, 40))}")
        except Exception as e:
            print(f"{label} - exception={repr(truncate(str(e), 90))}")

        index += 1

    for c in commands:
        run(c, shell=True)
        run(c, shell=False)

输出如下所示:

0 ) subprocess.run(['where', 'find.exe'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)                                 - returncode=0 - 'D:\\sources\\personal\\sublimemerge\\Git\\...'
1 ) subprocess.run(['where', 'find.exe'], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)                                - returncode=0 - 'D:\\sources\\personal\\sublimemerge\\Git\\...'
2 ) subprocess.run('where find.exe', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)                                      - returncode=0 - 'D:\\sources\\personal\\sublimemerge\\Git\\...'
3 ) subprocess.run('where find.exe', shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)                                     - returncode=0 - 'D:\\sources\\personal\\sublimemerge\\Git\\...'
4 ) subprocess.run(['c:\\windows\\system32\\where.exe', 'find.exe'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)      - returncode=0 - 'D:\\sources\\personal\\sublimemerge\\Git\\...'
5 ) subprocess.run(['c:\\windows\\system32\\where.exe', 'find.exe'], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)     - returncode=0 - 'D:\\sources\\personal\\sublimemerge\\Git\\...'
6 ) subprocess.run('c:\\windows\\system32\\where.exe find.exe', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)           - returncode=0 - 'D:\\sources\\personal\\sublimemerge\\Git\\...'
7 ) subprocess.run('c:\\windows\\system32\\where.exe find.exe', shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)          - returncode=0 - 'D:\\sources\\personal\\sublimemerge\\Git\\...'
8 ) subprocess.run(['find.exe', '--version'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)                             - returncode=0 - 'find (GNU findutils) 4.6.0\nCopyright ...'
9 ) subprocess.run(['find.exe', '--version'], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)                            - returncode=2 - 'FIND: Parameter format not correct\n'
10) subprocess.run('find.exe --version', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)                                  - returncode=0 - 'find (GNU findutils) 4.6.0\nCopyright ...'
11) subprocess.run('find.exe --version', shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)                                 - returncode=2 - 'FIND: Parameter format not correct\n'
12) subprocess.run('D:\\sources\\personal\\sublimemerge\\Git\\usr\\bin\\find.exe --version', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - returncode=0 - 'find (GNU findutils) 4.6.0\nCopyright ...'
13) subprocess.run('D:\\sources\\personal\\sublimemerge\\Git\\usr\\bin\\find.exe --version', shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - returncode=0 - 'find (GNU findutils) 4.6.0\nCopyright ...'

我想到的第一个问题是,为什么我需要指定完整的可执行路径shell=False?为什么是env不以与当时相同的方式考虑shell=True用来?其实...看案例5,7,只要看一下那些人就会想到env正在考虑之中。

我想整个问题可以归结为理解如何env被给予创建进程 https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa在cpython中调用_winapi.c https://github.com/python/cpython/blob/b8f4163da30e16c7cd58fe04f4b17e38d53cd57e/Modules/_winapi.c.


None

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

subprocess.Popen 如何在 Windows 上与 shell=False 一起使用? 的相关文章

随机推荐