有没有一种简单的方法可以为一个glob设置nullglob

der*_*ert 21 bash glob shopt

在bash中,如果你这样做:

mkdir /tmp/empty
array=(/tmp/empty/*)
Run Code Online (Sandbox Code Playgroud)

你发现array现在有一个元素"/tmp/empty/*",而不是你想要的零.值得庆幸的是,可以使用打开nullglob shell选项来避免这种情况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
Run Code Online (Sandbox Code Playgroud)

让我觉得必须有一个更好的方法.明显的"把它放在子shell中"不起作用,因为变量赋值与子shell一起消失.除了等待Austin组导入ksh93语法之外,还有吗?

est*_*ani 16

完成后取消设置:

shopt -u nullglob
Run Code Online (Sandbox Code Playgroud)

并妥善(即存储以前的状态):

shopt -u | grep -q nullglob && changed=true && shopt -s nullglob
... do whatever you want ...
[ $changed ] && shopt -u nullglob; unset changed
Run Code Online (Sandbox Code Playgroud)


Mic*_*pat 9

随着mapfile在猛砸4,你可以加载一个子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
Run Code Online (Sandbox Code Playgroud)
  • 使用打印文件名时,请务必使用glob ./*而不是裸*echo
  • 不适用于文件名中的换行符:(正如derobert指出的那样)

如果您需要处理文件名中的换行符,则必须执行更详细的操作:

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

但就此而言,遵循其他答案之一的建议可能更为简单.


小智 6

这比你原来的建议好一点:

local nullglob = $(shopt -p nullglob); shopt -s nullglob

... 做你想做的 ...

$ nullglob; unset nullglob