2014-02-19 184 views
1

我想通過bash腳本遍歷指定擴展名列表的文件。我試着在Matching files with various extensions using for loop給出的解決方案,但它不按預期工作。給出的解決方案是:在bash中循環遍歷指定擴展名的文件

for file in "${arg}"/*.{txt,h,py}; do 

這裏是我的版本是:

for f in "${arg}"/*.{epub,mobi,chm,rtf,lit,djvu} 
    do 
     echo "$f" 
    done 

當我運行這個目錄中有一個epub文件在裏面,我得到:

/*.epub 
/*.mobi 
/*.chm 
/*.rtf 
/*.lit 
/*.djvu 

所以我試着改變for聲明:

for f in "${arg}"*.{epub,mobi,chm,rtf,lit,djvu} 

然後我:

089281098X.epub 
*.mobi 
*.chm 
*.rtf 
*.lit 
*.djvu 

我也得到相同的結果:

for f in *.{epub,mobi,chm,rtf,lit,djvu} 

如此看來,在"${arg}"說法是不必要的。

雖然這些語句中的任何一個都能找到指定擴展名的文件,並且可以將它們傳遞給程序,但是我從無法解析的*.文件名中讀取錯誤。

我正在使用OS X Mountain Lion。我意識到默認的bash shell已經過時了,所以我使用homebrew將它從3.2.48升級到4.2.45,看看是否是這個問題。這沒有幫助,所以我想知道爲什麼我得到這些意想不到的結果。給定的解決方案是錯誤的還是 bash shell與*NIX版本不同?有沒有其他方法可以完成同樣的事情,在OS X bash shell中可能會更好?

+0

嗨。你能否更詳細地解釋你想要做什麼?由於代碼被破壞,很難使用*作爲你想要的描述。 – jpaugh

回答

2

這可能是BASH 4.2ism。它在我的BASH中仍不起作用,它仍然是3.2。但是,如果您shopt -s extglob,你可以使用*(...)代替:

shopt -s extglob 
for file in *.*(epub|mobi|chm|rtf|lit|djvu) 
do 
    ... 
done 

@David W.: shopt -s extglob for f in .(epub|mobi|chm|rtf|lit|djvu) results in: 089281098X.epub @kojiro: arg=. shopt -s nullglob for f in "${arg}"/.{epub,mobi,chm,rtf,lit,djvu} results in: ./089281098X.epub shopt -s nullglob for f in "${arg}".{epub,mobi,chm,rtf,lit,djvu} results in: 089281098X.epub So all of these variations work but I don't understand why. Can either of you explain what is going on with each variation and what ${arg} is doing? I would really like to understand this so I can increase my knowledge. Thanks for the help.

在礦井:

for f in *.*(epub|mobi|chm|rtf|lit|djvu) 

我不包括${arg}它擴展到$arg值。 *(...)與任何一系列擴展之一中的圓括號中的模式相匹配。因此,它匹配*.epub

小次郎的:

arg=. 
shopt -s nullglob 
for f in "${arg}"/*.{epub,mobi,chm,rtf,lit,djvu} 

是包括$arg和他匹配的斜線。因此,koriro以./開頭,因爲這就是他們所要求的。

這就像之間的差別:順便說

echo * 

echo ./* 

,你可以與其他表達式就此別過:

echo *.*(epub|mobi|chm|rtf|lit|djvu) 

外殼做所有的擴展爲你。這與for聲明本身無關。

+0

+1啊,是的,可愛的'extglob'。我忘了它有這個表達。 – kojiro

+0

@David W .:謝謝你的解釋。順便說一句'echo *。*(epub | mobi | chm | rtf | lit | djvu)'給出錯誤:'-bash:語法錯誤附近的意外標記'(''。我不知道爲什麼。 – hmj6jmh

+0

你有'shopt -s extglob' set?由於某些原因,Bash不會自動擴展blobbing。 –

-1

這應做到:

for file in $(find ./ -name '*.epub' -o -name '*.mobi' -o -name '*.chm' -o -name '*.rtf' -o -name '*.lit' -o -name '*.djvu'); do 
    echo $file 
done 
+2

-1解析'find'的輸出與解析'ls'差不多[http://mywiki.wooledge.org/ParsingLs]。如果任何找到的文件名稱中有空格,它將會中斷。另外,如果'find'是正確的答案,那麼只要執行'find ./ -name'* .epub'-name ...',然後讓find進行打印。 – kojiro

+0

@kojiro 1.你在開玩笑嗎?該文章提供的唯一解決方案是使用glob。不完全是最靈活的解決方案,特別是如果您需要處理子目錄時。 2. OP有一個「無理由」的循環去抱怨他們。我正在假設for循環對於他們實際想要完成的任何事情都是必需的。 – Sammitch

+0

我支持我說的 - 循環使用wordsplit命令替換很少是一個好主意。 1. glob非常靈活,特別是像nullglob,extglob和globstar這樣的擴展,但即使沒有它們,也不清楚OP是否需要緩存。 2.再次,如果'find'是正確的答案,則整個答案可以用'find'來表示。如果'find ... -print'不正確,'find ... -exec'是。除此之外,'find ... -print0 | xargs -0 ...'。 – kojiro

0

一個水珠已擴大到現有的,發現的名稱,或者是帶星號的完整單獨留在家中。如果你有一個空目錄,*.foo將擴大到*.foo。 (除非您使用nullglob Bash擴展名。)

您的代碼的問題在於,您以參數$arg開頭,該參數顯然爲空或未定義。因此,您的glob,${arg}/*.epub擴展爲/*.epub,因爲根目錄中沒有以「.epub」結尾的文件。它從不在當前目錄中查看。爲此,您需要首先設置arg=.

在第二個示例中,${arg}*.epub確實展開,因爲$arg爲空,但其他文件不存在,因此它們不會繼續展開爲球形。正如我之前暗示的,一個簡單的解決方法是使用shopt -s nullglob激活nullglob。這是bash特定的,但如果沒有匹配文件,將導致*.foo展開爲空字符串。對於嚴格的POSIX解決方案,您必須使用[ -f "$f" ]來過濾未擴展的球體。 (然後,如果你想要POSIX,你也不能使用支撐擴展。)

+0

@David W .:'shopt -s extglob' 'for f in *。*(epub | mobi | chm | rtf | lit | djvu)' 結果於: '089281098X。epub' @kojiro: 'ARG = .' '禁用了javascript -s nullglob' '對於F中的 「$ {arg}裏」/ * {EPUB,摩比,CHM,RTF,上火,DjVu的}' 結果英寸: '/ 089281098X.epub' '禁用了javascript -s nullglob' '對於F中的 「$ {} ARG」 * {EPUB,摩比,CHM,RTF,上火,DjVu的}' 結果: ' 089281098X.epub' 所以所有這些變化的工作,但我不明白爲什麼。你們中的任何一個都可以解釋每種變體的情況以及'$ {arg}'在做什麼?我真的很想理解這個,所以我可以增加我的知識。 感謝您的幫助。 – hmj6jmh

+0

請參閱我的原始答案附加。 –

0

總之,最好的解決方案是使用(最直觀,最優雅):

shopt -s extglob 
for f in *.*(epub|mobi|chm|rtf|lit|djvu) 

,或者在用被引用的線程(這是錯誤的,因爲說明)給出的原液保持:

shopt -s nullglob 
for f in "${arg}"*.{epub,mobi,chm,rtf,lit,djvu} 
相關問題