如果我想检查单个文件是否存在,我可以使用test -e filename或[-e filename]进行测试。

假设我有一个glob,我想知道是否有文件名与glob匹配的文件存在。glob可以匹配0个文件(在这种情况下,我不需要做任何事情),也可以匹配1个或多个文件(在这种情况下,我需要做一些事情)。我如何测试一个glob是否有任何匹配?(我不在乎有多少匹配,这将是最好的,如果我能做到这一点与一个if语句和没有循环(只是因为我发现最易读)。

(如果glob匹配多个文件,则test -e glob*失败。)


当前回答

如果你有globfail集,你可以使用这个疯狂的(你真的不应该)

shopt -s failglob # exit if * does not match 
( : * ) && echo 0 || echo 1

or

q=( * ) && echo 0 || echo 1

其他回答

nullglob shell选项实际上是bashism。

为了避免繁琐的保存和恢复nullglob状态,我只在扩展glob的subshell中设置它:

if test -n "$(shopt -s nullglob; echo glob*)"
then
    echo found
else
    echo not found
fi

为了获得更好的可移植性和更灵活的通配符,使用find:

if test -n "$(find . -maxdepth 1 -name 'glob*' -print -quit)"
then
    echo found
else
    echo not found
fi

显式-print -quit操作用于查找,而不是默认的隐式-print操作,以便查找在找到第一个匹配搜索条件的文件时立即退出。当许多文件匹配时,这应该比echo glob*或ls glob*运行得快得多,并且它还避免了过度填充扩展命令行的可能性(一些shell有4K长度限制)。

如果find感觉有点多余,可能匹配的文件数量很少,请使用stat:

if stat -t glob* >/dev/null 2>&1
then
    echo found
else
    echo not found
fi

基于flabdablet的答案,对我来说,它看起来最简单的(不一定是最快的)就是使用find本身,同时在shell上留下glob展开,像:

find /some/{p,long-p}ath/with/*globs* -quit &> /dev/null && echo "MATCH"

或者在if like中:

if find $yourGlob -quit &> /dev/null; then
    echo "MATCH"
else
    echo "NOT-FOUND"
fi

如果你想在遍历这些文件之前测试它们是否存在,你可以使用这个模式:

  for F in glob*; do
    if [[ ! -f $F ]]; then break; fi
    
    ...

  done

如果glob不匹配任何内容,$F将是未展开的glob(在本例中为'glob*'),如果同名文件不存在,则跳过循环的剩余部分。

根据miku的想法,简化一下他的回答:

M=(*py)
if [ -e ${M[0]} ]; then
  echo Found
else
  echo Not Found
fi

在Bash中扩展glob (extglob)的解决方案:

bash -c $'shopt -s extglob \n /bin/ls -1U <ext-glob-pattern>'

如果至少有一个匹配,则退出状态为0,如果没有匹配,则退出状态为非0(2)。标准输出包含一个换行分隔的匹配文件列表(以及文件名中包含引号中的空格)。

或者,稍微不同:

bash -c $'shopt -s extglob \n compgen -G <ext-glob-pattern>'

与基于ls的解决方案的区别:可能更快(未测量),输出中未引用空格的文件名,不匹配时退出代码1(而不是2:shrug:)。

使用示例:

不匹配:

$ bash -c $'shopt -s extglob \n /bin/ls -1U @(*.foo|*.bar)'; echo "exit status: $?"
/bin/ls: cannot access '@(*.foo|*.bar)': No such file or directory
exit status: 2

至少一种匹配:

$ bash -c $'shopt -s extglob \n /bin/ls -1U @(*.ts|*.mp4)'; echo "exit status: $?"
'video1 with spaces.mp4'
video2.mp4
video3.mp4
exit status: 0

概念:

ls的退出代码行为(添加-U表示效率,-1表示输出控制)。 在当前shell中不启用extglob(通常不需要)。 使用$前缀使\n被解释,因此扩展的glob模式与shopt -s extglob在不同的行上——否则扩展的glob模式将是一个语法错误!

注1:我致力于这个解决方案,因为在其他答案中建议的compgen -G“<glob-pattern>”方法似乎不能顺利地与大括号展开一起工作;但我需要一些更高级的globing功能。

注2:扩展的glob语法的可爱资源:extglob