我学习了 bash,使用通配符遇到了下一个问题:
sergs:~ > ls -1
a.sh
Desktop
Downloads
eclipse
sergs:~ > a=*.sh
sergs:~ > echo $a
a.sh
sergs:~ > a=*.sha
sergs:~ > echo $a
*.sha
如果没有文件与 *.sha
模式匹配,为什么 bash
返回模式本身而不是不返回任何内容?
因此行为打破了这样的逻辑:
for i in /usr/lib/opkg/info/*.postinst; do do_some_logic_with_postinst_file; done
我是否必须在循环之前明确检查 /usr/lib/opkg/info/
目录是否没有任何 *.postinst
文件,或者有一些其他方法来做到这一点。
最佳答案
除非您打开扩展 shell 选项 nullglob
,否则在命令行中按字面返回未扩展的 glob 字符串,该选项在 glob 扩展失败时不返回任何结果。
对于您的用例来说,通过测试扩展结果是否是一个文件来检查 for 循环中的 glob 扩展是否成功始终是一个好习惯,即
for file in /usr/lib/opkg/info/*.postinst; do
[ -f "$file" ] || continue
do_some_logic_with_postinst_file
done
条件 [ -f "$file"]
将检查您的 glob 扩展,即是否有任何 .postinst
文件 [ -f "$file"]
为真。对于未扩展的 glob,条件
[ -f /usr/lib/opkg/info/*.postinst ]
将失败,因为文字字符串 /usr/lib/opkg/info/*.postinst
不是有效文件,并且此 test
命令失败 bool OR ||
导致 for
循环执行 continue
操作。由于 for
循环不再需要处理任何参数,因此循环会正常退出。
这样做(使用 -f
针对 glob 字符串)可以保证符合 POSIX 标准。不过,对于 bash 特定答案,您可以打开前面提到的选项
# '-s' enables the option
shopt -s nullglob
for file in /usr/lib/opkg/info/*.postinst; do
do_some_logic_with_postinst_file
done
# '-u' disables the option
shopt -u nullglob
一旦您决定使用 nullglob
选项,您可以通过多种方式使用它来运行您的功能。例如您可以将所有 glob 结果放入数组类型中并检查长度是否有效
shopt -s nullglob
results=(/usr/lib/opkg/info/*.postinst)
if (( ${#results[@]} )); then
printf '%s\n' 'my array is not empty'
for file in "${results[@]}"; do
printf '%s\n' "some action on ${file}"
done
fi
shopt -u nullglob
不使用 nullglob
选项时请小心这种方法。如果没有相同的内容,results=(/usr/lib/opkg/info/*.postinst)
部分仍然可能是非空的,因为文字字符串仍然存储在数组中。
你的OP的另一个小附录是永远不要使用变量来保存你的glob字符串。因为当变量不带引号展开时,如果全局展开成功,则变量的内容会受到 shell 完成的分词的影响,并且包含空格的文件名可能会在您希望不分解时分解为多个条目。
始终使用数组和正确的带引号的扩展。查看更多 BashFAQ - BashGuide/Arrays有关该主题的精彩读物。
关于bash - bash 如何处理不匹配的通配符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57353542/