我试图检查一个文件是否存在,但与通配符。以下是我的例子:
if [ -f "xorg-x11-fonts*" ]; then
printf "BLAH"
fi
我也试过不加双引号。
我试图检查一个文件是否存在,但与通配符。以下是我的例子:
if [ -f "xorg-x11-fonts*" ]; then
printf "BLAH"
fi
我也试过不加双引号。
当前回答
如果网络文件夹中有大量文件,使用通配符是有问题的(速度,或命令行参数溢出)。
最后我得到了:
if [ -n "$(find somedir/that_may_not_exist_yet -maxdepth 1 -name \*.ext -print -quit)" ] ; then
echo Such file exists
fi
其他回答
下面是针对您的特定问题的解决方案,它不需要for循环或ls、find等外部命令。
if [ "$(echo xorg-x11-fonts*)" != "xorg-x11-fonts*" ]; then
printf "BLAH"
fi
正如您所看到的,它只是比您希望的稍微复杂一些,并且依赖于这样一个事实,即如果shell不能展开glob,这意味着不存在具有该glob的文件,echo将按原样输出glob,这允许我们仅做字符串比较来检查是否存在这些文件。
但是,如果我们要概括这个过程,我们应该考虑到这样一个事实,即文件的名称和/或路径中可能包含空格,并且glob char可以合理地扩展为零(在您的示例中,这将是文件名正好为xorg-x11-fonts的文件的情况)。
这可以通过bash中的以下函数来实现。
function doesAnyFileExist {
local arg="$*"
local files=($arg)
[ ${#files[@]} -gt 1 ] || [ ${#files[@]} -eq 1 ] && [ -e "${files[0]}" ]
}
回到您的示例,可以像这样调用它。
if doesAnyFileExist "xorg-x11-fonts*"; then
printf "BLAH"
fi
Glob展开应该发生在函数内部,以便它正常工作,这就是为什么我把参数放在引号中,这就是函数体中的第一行:因此任何多个参数(可能是函数外部Glob展开的结果,以及一个虚假的形参)将合并为一个。另一种方法是,如果有多个实参,就引发错误,还有一种方法是忽略除第一个实参以外的所有实参。
函数体中的第二行将files var设置为由glob扩展到的所有文件名组成的数组,每个数组元素对应一个文件名。如果文件名包含空格是可以的,每个数组元素将按原样包含文件名,包括空格。
函数体中的第三行做了两件事:
It first checks whether there's more than one element in the array. If so, it means the glob surely got expanded to something (due to what we did on the 1st line), which in turn implies that at least one file matching the glob exist, which is all we wanted to know. If at step 1. we discovered that we got less than 2 elements in the array, then we check whether we got one and if so we check whether that one exist, the usual way. We need to do this extra check in order to account for function arguments without glob chars, in which case the array contains only one, unexpanded, element.
如果您的shell有一个nullglob选项,并且该选项被打开,则不匹配任何文件的通配符模式将从命令行中完全删除。这将使ls看不到任何pathname参数,列出当前目录的内容并成功,这是错误的。如果没有参数或参数命名了一个不存在的文件,GNU stat总是会失败,它将更加健壮。另外,&>重定向操作符是bashism。
if stat --printf='' /path/to/your/files* 2>/dev/null
then
echo found
else
echo not found
fi
更好的是GNU find,它可以在内部处理通配符搜索,并在找到一个匹配文件时立即退出,而不是浪费时间处理由shell扩展的潜在的巨大列表;这也避免了shell可能溢出其命令行缓冲区的风险。
if test -n "$(find /dir/to/search -maxdepth 1 -name 'files*' -print -quit)"
then
echo found
else
echo not found
fi
非gnu版本的find可能没有此处使用的-maxdepth选项,以使find只搜索/dir/to/search,而不是整个目录树。
我发现了一些值得分享的巧妙解决方案。第一个仍然存在“如果匹配太多就会破坏”的问题:
pat="yourpattern*" matches=($pat) ; [[ "$matches" != "$pat" ]] && echo "found"
(回想一下,如果你使用一个没有[]语法的数组,你会得到数组的第一个元素。)
如果你在你的脚本中有"shop -s nullglob",你可以简单地这样做:
matches=(yourpattern*) ; [[ "$matches" ]] && echo "found"
现在,如果一个目录中可能有大量的文件,你很可能会使用find:
find /path/to/dir -maxdepth 1 -type f -name 'yourpattern*' | grep -q '.' && echo 'found'
您还可以删除其他文件
if [ -e $( echo $1 | cut -d" " -f1 ) ] ; then
...
fi
for i in xorg-x11-fonts*; do
if [ -f "$i" ]; then printf "BLAH"; fi
done
这将适用于多个文件,文件名中有空白。