bash 如何处理不匹配的通配符?

How does bash treat unmatched wildcard?

我学会了 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 return 模式本身而不是什么都没有?

因此行为打破了这样的逻辑:

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 扩展失败,returns 则不会产生任何结果。

尽管如此,对于您的用例,通过测试扩展结果是否为文件来检查 glob 扩展在 for 循环中是否成功始终是一个好习惯,即

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 命令与布尔 OR || 一起失败会导致 continue for 循环的动作。由于 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 字符串。因为当变量不加引号扩展并且 glob 扩展成功时,变量的内容会受到 shell 完成的分词的影响,并且包含空格的文件名可能会在您期望时分解为多个条目它不是。

始终使用数组和适当的引用扩展。在 BashFAQ - BashGuide/Arrays 上查看更多关于该主题的优秀读物。

这就是 glob 模式的工作原理(编辑:除非您启用 nullglob,正如 Inian 指出的那样)。另一种选择可以是

find /usr/lib/opkg/info -name \*.postinst|while read file; do
   # do_some_logic_with_postinst_file
done```