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

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

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


当前回答

set -- glob*
if [ -f "$1" ]; then
  echo "It matched"
fi

解释

当没有匹配glob*时,$1将包含'glob*'。test -f "$1"不会为真,因为glob*文件不存在。

为什么这比其他选择更好

这适用于sh和衍生品:KornShell和Bash。它不会创建任何子壳。$(..)和'…'命令创建子shell;它们分叉一个进程,因此比这个解决方案慢。

其他回答

我还有另一个解决方案:

if [ "$(echo glob*)" != 'glob*' ]

这对我来说很有用。我可能漏掉了一些极端情况。

假设你可能想对文件做些什么,如果它们存在:

mapfile -t exists < <(find "$dirName" -type f -iname '*.zip'); [[ ${#exists} -ne 0 ]] && { echo "Zip files found" ; } || { echo "Zip files not found" ; }

然后,如果需要对文件做些什么,就可以遍历exists数组。

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
[ `ls glob* 2>/dev/null | head -n 1` ] && echo true
#!/bin/bash
set nullglob
touch /tmp/foo1 /tmp/foo2 /tmp/foo3
FOUND=0
for FILE in /tmp/foo*
do
    FOUND=$((${FOUND} + 1))
done
if [ ${FOUND} -gt 0 ]; then
    echo "I found ${FOUND} matches"
else
    echo "No matches found"
fi