在 Bash if 条件中,如何检查是否存在与简单通配符表达式匹配的任何文件?

Jon*_*nik 10 ls bash wildcards files

愚蠢的是,我一直在使用这样的条件作为脚本的一部分:

if [ $(ls FOO* 2> /dev/null) ] # if files named "FOO*" were downloaded 
then
    echo "Files found" 
    # ... process and email results
else
    echo "Not found"
    # ... email warning that no files were found (against expectations)
fi
Run Code Online (Sandbox Code Playgroud)

这适用于零个和一个名为 的文件FOO*,但如果有多个则失败。从日志中,我发现了几个不同的错误消息:

[: FOO_20131107_082920: unary operator expected
[: FOO_20131108_070203: binary operator expected
[: too many arguments
Run Code Online (Sandbox Code Playgroud)

我的问题是:在 Bashif条件下,检查名称以 开头的一个或多个文件是否FOO存在的正确方法是什么?

GNU bash,版本 4.2.25(1)-release (x86_64-pc-linux-gnu)

Chr*_*own 21

发生这种情况是因为您对 ls 的命令替换会输出空格,并且它最终会在传递给[. 一种不太容易破坏的方法是将文件放在一个数组中,然后检查该数组是否至少有一个成员。

shopt -s nullglob

files=( FOO* )
if (( ${#files[@]} )); then
    # there were files
fi
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为((默认情况下,如果该值不等于 0,则返回 true,并${#files[@]}获取数组中的项目数(如果有与 glob 匹配的文件,则为 >0)。

你也可以做这样的事情,只要nullglob没有设置:

if ls FOO* >/dev/null 2>&1; then
    # there were files
fi
Run Code Online (Sandbox Code Playgroud)

这只是检查 的退出代码ls,如果您传递的文件名不存在FOO*,则该代码将为 1(文字,如果没有匹配的内容(当然,除非您是邪恶的并且有一个名为 的文件FOO*,在这种情况下它)将返回 0 :-) ))。

请注意,这两者也匹配目录。如果您真的只想匹配常规文件,则需要测试:

for file in FOO*; do
    if [[ -f $file ]]; then
        # file found, do some stuff and break
        break
    fi
done
Run Code Online (Sandbox Code Playgroud)


小智 5

上面的多行答案不适合我对单行解决方案而不是修改环境的渴望。这是一个可能适合您的通用单线:

echo $(ls FOO* 2>/dev/null | wc -w)
Run Code Online (Sandbox Code Playgroud)

/dev/null 是因为ls如果没有文件会引发错误。这只是忽略 ls 并根据“单词”(真正的文件名)的数量计算找到的文件数量。您可以在简单的 if 语句中使用它:

if [ 0 -lt $(ls FOO* 2>/dev/null | wc -w) ]; then
 echo "Some FOO is there."
fi
Run Code Online (Sandbox Code Playgroud)

这种方法具有灵活性,不仅可以检查是否存在任何匹配文件,还可以选择检查存在多少匹配文件(只需更改0和/或-lt),然后在此基础上进一步进行。

我没有检查包含通配符或空格的文件/文件夹;我怀疑上述方法尤其会给出错误的空格计数,如果需要超过 0 的准确计数,这只是一个问题。我为此尝试的一个解决方法是使用$(ls -l FOO* 2>/dev/null | wc -l),它将按行分解列表,因此应该是更能接受留白。

  • 您的答案与@ChrisDown 的不同,因为您解析了 `ls` 输出,而他没有(他只检查其退出状态)。由于 [解析 ls 输出](http://mywiki.wooledge.org/ParsingLs) 的复杂性,ChrisDown 完全避免它这一事实使他的答案比您的更可靠和正确,即使您的答案将适用于许多涉及“合理”文件名(即不包含空格)的情况。 (2认同)