subprocess.Popen 返回随机结果
我写了一段简单的代码:
import subprocess
p=subprocess.Popen('mkdir -p ./{a,b,c}', shell=True, stderr=subprocess.STDOUT)
p.wait()
可惜它的表现并不总是如我所愿。比如,当我在我的电脑上运行时,一切正常(ls -l 命令显示我有三个文件夹:a、b 和 c)。但是当我的同事在他的电脑上运行时,他看到的却是一个名为 '{a,b,c}' 的文件夹……我们俩都在用 Python 2.7.3。为什么会这样呢?你会怎么解决这个问题?
我试着自己找答案。根据手册的说法:“args 应该是程序参数的一个序列,或者是一个单独的字符串。默认情况下,如果 args 是一个序列,程序会执行 args 中的第一个项目。如果 args 是一个字符串,那么它的解释会依赖于平台,具体情况在下面描述。有关与默认行为的其他差异,请参见 shell 和可执行参数。除非另有说明,建议将 args 作为一个序列传递。”
所以我试着在 shell 中执行这段代码:
python -c "import subprocess; p=subprocess.Popen(['mkdir', '-p', './{ea,fa,ga}'], shell=True, stderr=subprocess.STDOUT); p.wait()"
结果是:
mkdir: missing operand
我会很感激任何建议
谢谢!
4 个回答
根据我的理解,os.mkdir(path,[mode]) 这个方法在处理跨平台项目时使用起来更安全。
os.mkdir(os.getcwd()/a)
不过,它的使用方式没有用子进程的方法那么优雅。
这里有几个问题。
- 首先:如果你使用的是一系列参数,记得不要把“shell = True”设置为真(这是Popen手册中推荐的做法)。把它设置为假,你会发现你的mkdir命令会被接受。
- “./{a,b,c}”是我所知道的在bash中的一种特定语法。如果你的同事使用的是其他类型的shell,这个命令可能就不管用,或者表现得不一样。
- 你应该使用Python的“mkdir”命令,而不是调用shell命令,这样无论服务器、shell还是操作系统是什么,都能正常工作。
谢谢大家的回答。
看起来,最好的方法就是直接使用 /bin/sh 的语法。我把我的代码改成了:
'mkdir -p ./a ./b ./c'
就像你们建议的那样。
我没有使用 mkdir() 这个函数,因为我在写一个包含很多系统调用的脚本,我想提供一个优雅的 --dry-run 选项(这样我就可以列出所有的命令)。
问题解决了 - 谢谢你们!
这个 ./{a,b,c}
的写法是 bash
的语法,不是所有的命令行都支持这种写法。
文档中提到:
在 Unix 系统中,如果使用
shell=True
,那么默认的命令行是/bin/sh
。如果参数是一个字符串,这个字符串就是要通过命令行执行的命令。
所以你的命令只有在 /bin/sh
链接到一个支持这种语法的命令行,比如 bash
或 zsh
时才能正常工作。你的同事可能在用 dash
或其他不支持这种语法的命令行。
你不应该依赖用户的默认命令行。相反,应该写出完整的命令,包含所有的展开内容:
p = subprocess.Popen('mkdir -p ./a ./b ./c', shell=True, stderr=subprocess.STDOUT)