2012-02-03 60 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

相关问题