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

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

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


当前回答

ls | grep - q“glob *。”

这不是最有效的解决方案(如果目录中有大量文件,它可能会比较慢),但它很简单,易于阅读,而且它的优点是正则表达式比普通的Bash glob模式更强大。

其他回答

if ls -d $glob > /dev/null 2>&1; then
  echo Found.
else
  echo Not found.
fi

请注意,如果有很多匹配或文件访问缓慢,这可能会非常耗时。

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

我喜欢

exists() {
    [ -e "$1" ]
}

if exists glob*; then
    echo found
else
    echo not found
fi

这既可读又有效(除非有大量的文件)。 主要的缺点是它比看起来要微妙得多,有时我觉得有必要添加一个很长的评论。 如果有匹配项,shell将展开“glob*”,并将所有匹配项传递给exists(),后者检查第一个匹配项并忽略其余匹配项。 如果没有匹配,则将"glob*"传递给exists()并发现它也不存在。

编辑:可能是假阳性,见评论

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

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

在Bash中是这样的(测试文件包含模式):

shopt -s nullglob
compgen -W *pattern* &>/dev/null
case $? in
    0) echo "only one file match" ;;
    1) echo "more than one file match" ;;
    2) echo "no file match" ;;
esac

它比compgen -G好得多:因为我们可以区分更多的情况,更精确。

它只能使用一个通配符*。