为什么 os.system 只读取命令的一部分?

Why os.system is reading only part of the command?

我有一个 Thumbnail_Handler class 有这个方法,应该 运行 Adob​​e Photoshop 的文件:

def abrir_photoshop(self):
        target = self.path_copia
        norm_path = os.path.normpath(r"C:\Program Files\Adobe\Adobe Photoshop 2021\Photoshop.exe")
        cmd = '"' + norm_path + '" "' + target + '"'
        print(cmd)
        proc = os.system(cmd)
        for filename in os.listdir(PATH_THUMBNAIL + self.nome_playlist):
            if re.match(self.id_video_original + '.*.png', filename):
                self.set_status(status_thumb.PNG_EXPORTADO)
                return filename

打印在 print(cmd) 行的命令是这样的:"C:\Program Files\Adobe\Adobe Photoshop 2021\Photoshop.exe" "C:\Users\adassa\Desktop\Thiago\Youtube Almir\\PSDs\Não Temas - 8PydQGvI0E4.psd"

如果我简单地复制它,然后粘贴到 Powershell,或者粘贴到常见的 Windows shell,它会按预期工作,但是当 python 运行s 命令,我得到: 'C:\Program' is not recognized as a command. 我认为这意味着命令没有双引号。为什么会发生这种情况,我该如何纠正?

mslex 包中的

mslex.quote 看起来像是您的案例的解决方案。

shelx.quote 在类 unix 系统上执行相同的任务。

当我尝试与您的路径类似的路径时,如果该路径不存在,它只会尝试 运行 'C:\Program',否则它工作正常,但是因为您说它在您手动复制时有效路径也许是别的东西。

我找到了两种强制正确路径的方法:

方案一:只引用部分路径

norm_path = os.path.normpath(r'C:\"Program Files\Adobe\Adobe Photoshop 2021\Photoshop.exe"')

解决方案 2:使用插入符号

转义 space
norm_path = os.path.normpath(r'C:\Program^ Files\Adobe\Adobe^ Photoshop 2021\Photoshop.exe')

os.system 调用 [MS.Docs]: system, _wsystem,后者又调用命令解释器 (cmd).

system 调用 cmd 时(我没有看到任何官方文档支持这一点,所以我将截图发布到支持我的说法),它 传递了 /c 参数 :

根据[MS.Docs]: cmdcmd /?强调是我的):

  • If you specify /c or /k, cmd processes, the remainder of string, and the quotation marks are preserved only if all of the following conditions are met:
    • You don't also use /s.
    • You use exactly one set of quotation marks.
    • You don't use any special characters within the quotation marks (for example: & < > ( ) @ ^ | ).
    • You use one or more white-space characters within the quotation marks.
    • The string within quotation marks is the name of an executable file.

If the previous conditions aren't met, string is processed by examining the first character to verify whether it is an opening quotation mark. If the first character is an opening quotation mark, it is stripped along with the closing quotation mark. Any text following the closing quotation marks is preserved.

因此,当传递一个 引用的可执行文件,后跟一个引用的参数时,cmd 改变命令 产生奇怪的结果看到了。

我不知道是否可以避免这种行为,(也许 symlinks 可以创建路径中没有空格并传递给 os.system),但这只是一个蹩脚的解决方法 (gainarie)。常识性方法是使用 [Python.Docs]: subprocess - Subprocess management.

code00.py:

#!/usr/bin/env python

import sys
import os
import subprocess


def quote(s):
    return '"' + s + '"'


def os_system(*args):
    cmd = " ".join(args)
    print("\nRun command: [{:s}]".format(cmd))
    return os.system(cmd)


def main(*argv):
    exe = os.path.normpath(r"c:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe")
    quoted_exe = quote(exe)
    files = [
        "e:\Work\Dev\Whosebug\q066659951\dummy_no_spaces.pdf",
        "e:\Work\Dev\Whosebug\q066659951\dummy with spaces.pdf",
    ]

    if len(argv):
        print("Using subprocess")
        for file in files:
            subprocess.call([exe, file])
        return 0

    os_system(quoted_exe)
    os_system(exe)
    for file in files:
        os_system(quoted_exe, file)
        os_system(quoted_exe, quote(file))


if __name__ == "__main__":
    print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    rc = main(*sys.argv[1:])
    print("\nDone.")
    sys.exit(rc)

输出:

[cfati@CFATI-5510-0:e:\Work\Dev\Whosebug\q066659951]> "e:\Work\Dev\VEnvs\py_pc064_03.08.07_test0\Scripts\python.exe" code00.py
Python 3.8.7 (tags/v3.8.7:6503f05, Dec 21 2020, 17:59:51) [MSC v.1928 64 bit (AMD64)] 64bit on win32


Run command: ["c:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe"]

Run command: [c:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe]
'c:\Program' is not recognized as an internal or external command,
operable program or batch file.

Run command: ["c:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe" e:\Work\Dev\Whosebug\q066659951\dummy_no_spaces.pdf]

Run command: ["c:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe" "e:\Work\Dev\Whosebug\q066659951\dummy_no_spaces.pdf"]
'c:\Program' is not recognized as an internal or external command,
operable program or batch file.

Run command: ["c:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe" e:\Work\Dev\Whosebug\q066659951\dummy with spaces.pdf]

Run command: ["c:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe" "e:\Work\Dev\Whosebug\q066659951\dummy with spaces.pdf"]
'c:\Program' is not recognized as an internal or external command,
operable program or batch file.

Done.

[cfati@CFATI-5510-0:e:\Work\Dev\Whosebug\q066659951]> :: !!! Now running via subprocess !!!
[cfati@CFATI-5510-0:e:\Work\Dev\Whosebug\q066659951]> "e:\Work\Dev\VEnvs\py_pc064_03.08.07_test0\Scripts\python.exe" code00.py 1
Python 3.8.7 (tags/v3.8.7:6503f05, Dec 21 2020, 17:59:51) [MSC v.1928 64 bit (AMD64)] 64bit on win32

Using subprocess

Done.

如所见:

  • 中的第1st运行(os.system),变体是工作是(引用可执行文件):

    • 没有参数
    • 使用不带引号的参数(但对于路径中有空格的文件,Acrobat Reader 无法打开它,因此它也失败了 - 但在后期)
  • 在第2nd一个(subprocess)中,一切顺利(和Acrobat Reader 打开文件没问题 - 在这方面你必须相信我 :) ),根本不需要额外的引用