shell 什么时候在表示Windows路径的Python字符串中混合使用路径分隔符才是“安全的”?

vojdkbi0  于 2023-02-24  发布在  Shell
关注(0)|答案(1)|浏览(104)

这个最小的例子:(在PyCharm调试器中运行)

import os
from os.path import join
import subprocess

src_path = r'C:/TEMP/source'
dest_path = r'C:/TEMP/dest'

if __name__ == "__main__":
    for root, _, files in os.walk(src_path):
        for name in files:
            src_file_path = join(root, name)
            rel_dest_file_path = os.path.join(dest_path, os.path.dirname(os.path.relpath(src_file_path, src_path)))
            rdfp = join(rel_dest_file_path, name)
            sfp = src_file_path
            cmd = "['copy', '/v', %s, %s]" % (sfp, rdfp)
            print 'calling shell subprocess %s' % cmd
            subprocess.call(['copy', '/v', sfp, rdfp], shell=True)

生成以下输出:

calling shell subprocess ['copy', '/v', C:/TEMP/source\foo bar.txt, C:/TEMP/dest\foo bar.txt]
1 file(s) copied.
calling shell subprocess ['copy', '/v', C:/TEMP/source\foo.txt, C:/TEMP/dest\foo.txt]
The syntax of the command is incorrect.

Process finished with exit code 0

为什么文件名为“foo bar.txt”的路径不会产生命令语法错误?为什么路径会导致成功的文件复制?
我可以通过在初始的原始字符串文本路径赋值中显式使用Windows路径分隔符来修复示例中的语法问题,这对我来说是有意义的。

src_path = r'C:\TEMP\source'
dest_path = r'C:\TEMP\dest'

令人不解的是,为什么“混合斜线”路径中的空格也能“解决”语法问题。
有什么参考资料或指示吗?

x7yiwoj4

x7yiwoj41#

简短的回答是:* * 保持一致,始终使用操作系统首选的分隔符。**不要依赖于意外发生的情况来保护您。
您的具体情况说明:在Windows系统中,程序是用一个字符串启动的,而不是像POSIX系统中那样用一个参数向量启动的。你传递了一个list作为命令,这意味着它必须被转换成一个字符串。Python用一个内部函数list2cmdline来完成这一操作。它在空参数以及任何包含空格或制表符的参数周围添加引号。结果是,你的代码只有在路径中有空格时才用引号括起来:

>>> print(subprocess.list2cmdline(['copy', '/v', r"C:/TEMP/source\foo bar.txt", r"C:/TEMP/dest\foo bar.txt"]))
copy /v "C:/TEMP/source\foo bar.txt" "C:/TEMP/dest\foo bar.txt"

>>> print(subprocess.list2cmdline(['copy', '/v', r"C:/TEMP/source\foo.txt", r"C:/TEMP/dest\foo.txt"]))
copy /v C:/TEMP/source\foo.txt C:/TEMP/dest\foo.txt

看起来copy的参数解析可以接受路径中的反斜杠,如果路径被引用,但不被引用,它会变得混乱(可能是因为解析器将未受保护的正斜杠视为引入了奇怪的开关)。
这里一个更普遍的规则是WinAPI调用可以使用混合分隔符,但是单个程序的参数解析可能不行。但是同样,首先跳过这个问题,使用os.path.joinos.sepPath对象的/重载等,而不是硬编码路径(除非路径受到操作系统的限制,无法存在于不匹配的操作系统上,例如,在您的情况下,您使用的是Windows,只有Windows路径,应该只使用带反斜杠的原始字符串常量)。

相关问题