子进程调用中shlex的通配符无效
语言:Python v2.6.2
操作系统:AIX 5.3
我正在用Python把一些文件从备份恢复到一个测试系统——下面的命令都是这样调用的,但有些就是不想工作。
#!/usr/bin/python
import subprocess, shlex
cmd = 'sudo rm -rf /work/TEST/*'
arg = shlex.split(cmd)
# This does not work
p = subprocess.Popen(arg)
# This, however, works just fine
p = subprocess.Popen(cmd, shell=True)
如果我把命令中的*去掉,它们就能正常工作(当然,没有通配符的情况下它们能正常工作,但这不是我想要的)。
我真的不想使用shell=True,出于明显的安全原因。不过还有其他几个命令基本上做同样的事情。如果命令中有通配符,它就是不工作——执行时没有错误,就是不做任何事情。
有趣的是,下面这个命令(通过shlex解析):
sudo mv /work/testrestore/production/* /work/TESTC
产生了以下结果:
mv: 0653-401 无法将 /work/testrestore/production/* 重命名为 /work/TESTC/*:路径中的某个文件或目录不存在。
感觉就像Unix现在在尝试移动一个名为*的文件,而不是把*当作通配符使用。这是shlex的典型行为吗?
编辑:我尝试用\来转义*,也试过把单引号换成双引号……虽然我并不指望这样能有什么效果。
1 个回答
5
要把*
替换成它真正的意思,你需要用到命令行工具或者glob
这个模块。所以最简单的方法就是使用shell=True
(如果命令是固定的,我觉得这样没有安全隐患)。
另一种方法是
#!/usr/bin/python
import subprocess
import shlex
import glob
cmd = 'sudo rm -rf /work/TEST/*'
arg = shlex.split(cmd)
arg = arg[:-1] + glob.glob(arg[-1])
# This should work now
p = subprocess.Popen(arg)
或者,如果你还是想自己手动添加路径的话,
cmd = 'sudo rm -rf'
basearg = shlex.split(cmd)
arg = basearg + glob.glob(path+"/*")