将从 os.walk 收到的路径放入到 Windows 终端上的 运行 的 cmd - python

Putting a path received from os.walk into a cmd to run on Windows terminal - python

我的代码有问题,如下所示:

def optimizer(dst, directory = r"G:\Attachments\Attachments" ):
    dst = " /d " + dst
    reducer = '"' + r"C:\Program Files (x86)\ORPALIS\PDF Reducer 3 Professional Edition\pdfreducer.exe" + '"' + " /q 2"

    for path, dirs, files in os.walk(directory):
        src = r" /f " + path
        cmd = reducer + src + dst
        subprocess.call(cmd)

optimizer(r"C:\Users\Desktop\ReducedPdfs")

我想做的是遍历给定目录中的所有目录并使用此命令优化 pdf: "C:\Program Files (x86)\ORPALIS\PDF Reducer 3 Professional Edition\pdfreducer.exe" /q 2 /f G:\Attachments\Attachments /d C:\Users\Desktop\ReducedPdfs.

问题出在我在上述方法中一起解析此命令时使用的 path 变量。如果我保留它,因为它是从 os.walk 返回的,它是一个普通字符串,然后斜线被视为转义序列。如果我将它包装在 repr() 中,那么它会被放入带有前导和尾随单引号 (') 和双反斜杠的 PDF Reducer 软件中,程序不知道如何处理。

我尝试用 re.sub() 和 .replace() 将反斜杠替换为正斜杠,但无济于事。 re.sub() 似乎不能很好地处理转义字符,当我使用 .replace() 时,我的程序没有 运行。使用 repr(),它 运行s,但表示该文件不存在于目标中。

subprocess 命令最适合作为参数列表而不是长字符串,这有助于避免某些问题(例如转义序列、其中包含空格的路径、引号等)

你应该使用这样的东西(并根据你的需要进行修改):

cmd = [reducer, '/q', '2', '/f', path, '/d', dst]
subprocess.call(cmd)

请注意,如果您是这样使用它的,像 pathdstreducer 这样的路径不需要用引号括起来,即使它们中有空格,因为您已经指定它们是此列表中的单个项目。

在您的代码中应该是这样的:

def optimizer(dst, directory = r"G:\Attachments\Attachments" ):
    reducer = r"C:\Program Files (x86)\ORPALIS\PDF Reducer 3 Professional Edition\pdfreducer.exe"

    for path, dirs, files in os.walk(directory):
        cmd = [reducer, '/q', '2', '/f', path, '/d', dst]
        subprocess.call(cmd)

optimizer(r"C:\Users\Desktop\ReducedPdfs")

如果您只需要过滤掉那些包含 pdf 文件的子文件夹,请执行以下操作:

for path, dirs, files in os.walk(directory):
    if any(f.endswith('.pdf') for f in files):
        cmd = [reducer, '/q', '2', '/f', path, '/d', dst]
        subprocess.call(cmd)

或者,没有 os.walk 的更快版本(使用 pathlib):

from pathlib import Path
paths = {str(f.parent) for f in Path(directory).rglob('*.pdf')}
for path in paths:
    cmd = [reducer, '/q', '2', '/f', path, '/d', dst]
    subprocess.call(cmd)