如果我有一个目录,我想删除除一个文件以外的所有文件,我可以在bash中执行此操作:
cd /tmp/a
rm -rf !(specialfile)
cd -
将此转换为最明显的Python代码对我来说失败了:
>>> subprocess.Popen( 'cd /tmp/a; rm -rf !(specialfile); cd -', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).communicate()
收到此消息:
('', "/bin/sh: -c: line 0: syntax error near unexpected token `('\n/bin/sh: -c: line 0: `cd /tmp/a; rm -rf !(specialfile); cd -'\n")
Python中的下一个最好的事情似乎是:
p = '/tmp/a'
for i in os.listdir( p ):
if i != 'specialfile':
os.remove( os.path.join( p, i ) )
但当然这并不能很好地处理文件和子目录。还有更好的方法吗?
答案 0 :(得分:2)
更新:正如@isedev和OP @JohnSchmitt在评论中指出的那样,subprocess.Popen
会调用sh
,而不是bash
(以及sh
可能或者可能不是bash
,具体取决于平台),但使用扩展模式匹配运算符!(...)
需要(a)bash
和(b)extglob
选项已转on(见下文背景)。
因此,答案是:
bash
命令行选项传递的命令字符串显式调用-c
。extglob
命令行选项打开-O
shell选项(没有它,glob !(specialfile)
会触发OP遇到的语法错误。)借用@ JohnSchmitt自己的评论,我们得到:
subprocess.Popen("bash -O extglob -c 'cd /tmp/a; rm -rf !(file2); cd -'",
stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).communicate()
(不太优雅的替代方法是在shopt -s extglob;
命令之前将rm
添加到bash命令字符串。)
<强>背景强>:
!(specialfile)
是扩展模式匹配运算符的实例(请参阅man bash
,Pattern Matching
部分);默认情况下,这些扩展运算符未启用; shopt -s extglob
启用它们(shopt -u extglob
禁用它们。)
答案 1 :(得分:1)
你可以使用os.walk作为@Bakuriu提到。非常重要的是从底部到顶部遍历目录树,以便始终具有空目录,但包含&#39; specialfile&#39;的目录除外。这就是为什么你需要try
命令中的os.rmdir
子句。
import os
for root, dirs, files in os.walk(top, topdown=False):
for name in files:
if name != 'specialfile':
os.remove(os.path.join(root, name))
for name in dirs:
try:
os.rmdir(os.path.join(root, name))
except:
pass