2012-02-03 29 views
18

在bash,如果你這樣做:有一種簡單的方法來設置對了nullglob一個水珠

mkdir /tmp/empty 
array=(/tmp/empty/*) 

你發現array現在有一個元素,"/tmp/empty/*",不爲零,只要你願意。值得慶幸的是,這可以通過打開使用了nullglob外殼選項可以避免shopt -s nullglob

不過了nullglob是全球性的,編輯現有的shell腳本時,可能會打破東西(例如,沒有人檢查ls foo*退出代碼來檢查是否有是以「foo」開頭的文件嗎?)。所以,理想情況下,我只想將它打開一個小範圍 - 理想情況下,一個文件名擴展。你可以關閉它再次使用shopt -u nullglob不過,當然,只有當它被禁用前:

old_nullglob=$(shopt -p | grep 'nullglob$') 
shopt -s nullglob 
array=(/tmp/empty/*) 
eval "$old_nullglob" 
unset -v old_nullglob 

讓我覺得必須有一個更好的辦法。顯而易見的「將它放在子外殼中」並不適用,因爲變量賦值與子外殼一起死亡。除了導入ksh93語法的waiting for the Austin group,有嗎?

回答

9

在Bash中4 mapfile,你可以從一個子shell加載陣列喜歡的東西:mapfile array < <(shopt -s nullglob; for f in ./*; do echo "$f"; done)。完整的示例:

$ shopt nullglob 
nullglob  off 
$ find 
. 
./bar baz 
./qux quux 
$ mapfile array < <(shopt -s nullglob; for f in ./*; do echo "$f"; done) 
$ shopt nullglob 
nullglob  off 
$ echo ${#array[@]} 
2 
$ echo ${array[0]} 
bar baz 
$ echo ${array[1]} 
qux quux 
$ rm * 
$ mapfile array < <(shopt -s nullglob; for f in ./*; do echo "$f"; done) 
$ echo ${#array[@]} 
0 
  • 請務必./*代替裸*到使用glob的時候echo要打印的文件名
  • 不中的文件名用換行符工作:(如指出, derobert

如果您需要處理換行符的文件名,你W¯¯生病必須做詳細得多:

array=() 
while read -r -d $'\0'; do 
    array+=("$REPLY") 
done < <(shopt -s nullglob; for f in ./*; do printf "$f\0"; done) 

但到了這一點,它可能是簡單的跟隨其他答案之一的意見。

+1

這很不錯。如果文件名中有換行符,它會失敗,但儘管允許,但這種情況非常罕見。只要文件名不受攻擊者控制。 – derobert 2013-12-14 15:09:52

+0

是的,文件名中的換行符確實存在。通常情況下,這隻意味着「找到罪魁禍首並懲罰他/她」。除了我唯一一次看到文件名中的換行符,罪魁禍首是一位迷人的老太太...... – mivk 2013-12-23 19:29:11

1

這可能接近你想要的;因爲它需要執行一個命令來擴展glob。

$ ls 
file1 file2 
$ array=($(shopt -s nullglob; ls foo*)) 
$ ls foo* 
ls: foo*: No such file or directory 
$ echo ${array[*]} 
file1 file2 

而是在子shell設置array,我們創建一個使用$()的輸出由array拍攝的子shell。

+5

不適用於空格(沒有意外):'touch「file1」「file 2」; array =($(shopt -s nullglob; ls foo *)); set | grep^array'產生'array =([0] =「file1」[1] =「file」[2] =「2」)' – derobert 2012-02-03 17:00:10

13

取消它完成時:

shopt -u nullglob 

,正確(即存儲之前的狀態):

shopt -u | grep -q nullglob && changed=true && shopt -s nullglob 
... do whatever you want ... 
[ $changed ] && shopt -u nullglob; unset changed 
+1

這樣做避免了eval,我沒有意識到-s和-u有這種行爲('幫助shopt'沒有提及它)。我爲這些贊成。但說實話,它並不是那麼簡單 - 就你必須記住要正確的方面而言,第一條線有很多。 – derobert 2012-02-03 17:07:11

+1

我從來沒有說過它更簡單:-)但它只是做你的問題,使用nullglob而不影響從同一會話啓動的其他腳本。記住nullglob的價值增加了​​複雜性,但它是您保持原有環境的唯一方式。 – estani 2012-02-03 18:27:22

+0

那麼,問題是爲了更好*或更容易*做到這一點(因爲問題中的第二個代碼示例也設法將設置恢復到之前的狀態)。顯然,我沒有在問題中說清楚 - 請提出如何改進它。 – derobert 2012-02-03 19:04:09

6

這比你原來的建議只是一點點更好:

地方了nullglob = $(禁用了javascript -p了nullglob); shopt -s nullglob

...做任何你想做的事......

$ nullglob;未設置了nullglob

0

這是我發現的最簡單的解決方案:

例如,擴大字面**/*.mp3成僅在特定變量水珠,可以使用

VAR=**/*.mp3(N) 

來源:https://unix.stackexchange.com/a/204944/56160

+1

請注意,這是一個在bash中找不到的zsh功能,這是OP指定的功能。 – ssmith 2017-01-14 22:17:58

相關問題