2014-03-13 136 views
0

通配符如果我有,我要刪除所有,但一個文件的目錄,我可能會在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() 

此消息:

​​

在Python退而求其次似乎是:

p = '/tmp/a' 
    for i in os.listdir(p): 
    if i != 'specialfile': 
     os.remove(os.path.join(p, i)) 

但當然這並不能很好地處理文件和子目錄。有沒有更好的辦法?

+3

你嘗試過:'subprocess.Popen( '的bash -c 「!CD的/ tmp/A;室射頻(specialfile)」',標準輸出= subprocess.PIPE,標準錯誤= subprocess.PIPE,殼= True).communicate()',理由是'shell = True'調用'/ bin/sh'不是bash(根據系統的不同,可能會也可能不同)。 – isedev

+0

看看:['os.walk'](http://docs.python.org/2/library/os.html#os.walk)。另外,從['Popen'](http://docs.python.org/2/library/subprocess.html#subprocess.Popen)的文檔中閱讀,您可以傳遞'executable'參數來指定應該是使用,這應該解決你的第一次嘗試。 – Bakuriu

+0

個人而言,我更喜歡「下一個最好的東西」 - 產生一個bash只是爲了清理層次結構似乎過分。要處理目錄,可以使用shutil.rmtree()。 – dstromberg

回答

1

你可以使用os.walk作爲@Bakuriu提到的。非常重要的是從底部到頂部遍歷目錄樹,以便總是清空目錄,除了包含'specialfile'的目錄之外。這就是爲什麼您需要os.rmdir命令中的try子句。

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 
+0

這就是我最終做的。我發佈了我的解決方案以及一個簡單的測試[here:](http://stackoverflow.com/a/22448874/1698426)。 –

+0

大@John Schmitt!總是樂於提供幫助。但是,不要忘記將答案標記爲選定的答案。 ;-) – Javier

2

更新:作爲@isedev和OP @JohnSchmitt在註釋中指出,subprocess.Popen調用sh,不bash(和sh可以是或可以不是bash,取決於平臺),但使用延長圖案匹配操作者的!(...)要求(a)bash與(b)extglob選項打開(請參閱下面的背景)。

因此,答案是:

  • 調用bash明確地經由-c命令行選項傳遞的命令串。
  • 接通extglob殼選項,經由-O命令行選項(沒有它,水珠!(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;到bash命令字符串,該rm命令之前)

背景

!(specialfile)是一個擴展的實例模式匹配運算符(請參閱man bash,部分Pattern Matching);這些擴展的運算符默認是不啓用的; shopt -s extglob使它們(shopt -u extglob禁用它們)。

+1

感謝您的提示。我得到它的唯一方法就是這樣:'subprocess.Popen(「bash -O extglob -c'cd/tmp/a; rm -rf!(file2); cd - '」,stdout = subprocess.PIPE, stderr = subprocess.PIPE,shell = True).communicate()' –

+1

@JohnSchmitt:感謝您的反饋 - 應該注意到'.Popen'使用'sh'而不是'bash'。用'bash -c',在命令字符串中加入'shopt -s extglob'應該可以工作,但是'-O extglob'方法實際上更加優雅;我會更新我的答案。 – mklement0