在bash中,如果您这样做:
mkdir /tmp/empty
array=(/tmp/empty/*)
您发现array
现在有一个元素"/tmp/empty/*"
,而不是您想要的零。值得庆幸的是,这可以通过使用shopt -s nullglob
打开nullglob shell选项来避免
但是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
让我觉得一定有更好的方法。显而易见的"把它放在子shell中"不起作用,因为变量赋值当然会随着子shell而消亡。除了等待Austin小组导入ksh93语法之外,还有什么吗?
完成后取消设置:
shopt -u nullglob
正确地(即存储以前的状态):
shopt -u | grep -q nullglob && changed=true && shopt -s nullglob
... do whatever you want ...
[ $changed ] && shopt -u nullglob; unset changed
使用Bash 4中的mapfile
,您可以从具有类似mapfile array < <(shopt -s nullglob; for f in ./*; do echo "$f"; done)
的子shell加载数组。完整示例:
$ 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
- 使用
echo
打印文件名时,请确保使用./*
而不是裸*
进行glob - 不适用于文件名中的换行符:(正如derobert所指出的
如果您需要处理文件名中的换行符,则必须执行更详细的操作:
array=()
while read -r -d $' '; do
array+=("$REPLY")
done < <(shopt -s nullglob; for f in ./*; do printf "$f "; done)
但在这一点上,遵循其他答案之一的建议可能会更简单。
这只是比您最初的建议好一点点:
local nullglob=$(shopt -p nullglob) ; shopt -s nullglob
做你想做的事。。。
$nullglob ; unset nullglob
这可能接近您想要的;按原样,它需要执行一个命令来展开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
,而是使用$()
创建一个子shell,其输出由array
捕获。
这是我找到的最简单的解决方案:
例如,要将文本**/*.mp3
扩展为仅用于特定变量的glob,可以使用
VAR=**/*.mp3(N)
来源:https://unix.stackexchange.com/a/204944/56160