如何在不使用shell=True的情况下进行Python子进程调用?
比如说,在/tmp文件夹里,我有一些文件,后缀是.txt、.doc和.jpg,我想一次性把它们删除,使用shred和subprocess这两个工具。
下面的代码可以完成这个任务:
subprocess.call('bash -c "shred -n 5 -uz /tmp/{*.txt,*.pdf,*.doc}"', shell=True)
我想知道如果不使用shell=True,怎么能做到这一点。我试过下面的代码:
subprocess.call(['bash', '-c', '"shred -n 10 -uz /tmp/{*.txt,*.pdf,*.doc}"'])
subprocess.call(['bash', '-c', 'shred', '-n 10', '-uz', '/tmp/{*.txt,*.pdf,*.doc}'])
有没有什么建议呢?
3 个回答
1
如果这个命令来自一个可信的来源,比如说是写死在代码里的,那么使用 shell=True
是没有问题的:
#!/usr/bin/env python
from subprocess import check_call
check_call("shred -n 10 -uz /tmp/{*.txt,*.pdf,*.doc}",
shell=True, executable='/bin/bash')
/bin/bash
是用来支持命令中的 {}
的。
这个命令并不会运行 /bin/sh
。
1
subprocess.call(['bash', '-c', 'shred -n 10 -uz /tmp/{*.txt,*.pdf,*.doc}'])
你可以通过以下方式查看一个命令是如何被展开和拆分的:
$ printf "Argument: %s\n" bash -c "shred -n 5 -uz /tmp/{*.txt,*.pdf,*.doc}"
Argument: bash
Argument: -c
Argument: shred -n 5 -uz /tmp/{*.txt,*.pdf,*.doc}
在更一般的情况下(虽然这里用得有点多),如果你对某个命令执行了什么以及用了哪些参数有疑问,可以使用strace这个工具:
$ cat script
import subprocess
subprocess.call('bash -c "shred -n 5 -uz /tmp/{*.txt,*.pdf,*.doc}"', shell=True)
$ strace -s 1000 -fe execve python script
...
execve("/bin/bash", ["bash", "-c", "shred -n 5 -uz /tmp/{*.txt,*.pdf,*.doc}"], [/* 49 vars */]) = 0
...
$
2
我觉得那位朋友说得很对(不过我自己还没试过)。不过如果你以后再遇到类似的问题,shlex.split(s) 可能会对你有帮助。它可以把字符串's'按照“类似于命令行的语法”进行分割。
In [3]: shlex.split(s)
Out[3]: ['bash', '-c', 'shred -n 5 -uz /tmp/{*.txt,*.pdf,*.doc}']