子进程调用中shlex的通配符无效

6 投票
1 回答
5343 浏览
提问于 2025-04-17 00:10

语言: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+"/*")

撰写回答