我试图检查一个文件是否存在,但与通配符。以下是我的例子:
if [ -f "xorg-x11-fonts*" ]; then
printf "BLAH"
fi
我也试过不加双引号。
我试图检查一个文件是否存在,但与通配符。以下是我的例子:
if [ -f "xorg-x11-fonts*" ]; then
printf "BLAH"
fi
我也试过不加双引号。
当前回答
人测试。
if [ -e file ]; then
...
fi
将工作目录和文件。
其他回答
严格来说,如果你只想打印“Blah”,下面是解决方案:
find . -maxdepth 1 -name 'xorg-x11-fonts*' -printf 'BLAH' -quit
这里有另一种方法:
doesFirstFileExist(){
test -e "$1"
}
if doesFirstFileExist xorg-x11-fonts*
then printf "BLAH"
fi
但我认为最优的是如下所示,因为它不会尝试对文件名进行排序:
if [ -z $(find . -maxdepth 1 -name 'xorg-x11-fonts*' -printf 1 -quit) ]
then
printf "BLAH"
fi
对于Bash脚本,最直接和最有效的方法是:
if compgen -G "${PROJECT_DIR}/*.png" > /dev/null; then
echo "pattern exists!"
fi
即使在有数百万个文件的目录中,这也会非常快地工作,而且不涉及新的子shell。
源
最简单的应该是依赖ls返回值(当文件不存在时,它返回非零):
if ls /path/to/your/files* 1> /dev/null 2>&1; then
echo "files do exist"
else
echo "files do not exist"
fi
我重定向ls输出,使其完全静音。
下面是一个同样依赖于glob展开的优化,但避免使用ls:
for f in /path/to/your/files*; do
## Check if the glob gets expanded to existing files.
## If not, f here will be exactly the pattern above
## and the exists test will evaluate to false.
[ -e "$f" ] && echo "files do exist" || echo "files do not exist"
## This is all we needed to know, so we can break after the first iteration
break
done
这与grok12的答案非常相似,但它避免了在整个列表中进行不必要的迭代。
PowerShell对通配符的处理方式是不同的,你可以像下面这样把它放在引号里:
If (Test-Path "./output/test-pdf-docx/Text-Book-Part-I*"){
Remove-Item -force -v -path ./output/test-pdf-docx/*.pdf
Remove-Item -force -v -path ./output/test-pdf-docx/*.docx
}
我认为这是有帮助的,因为最初问题的概念涵盖了一般的“shell”,而不仅仅是Bash或Linux,也适用于有相同问题的PowerShell用户。
下面是针对您的特定问题的解决方案,它不需要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.
恕我直言,最好在测试文件、glob或目录时使用find always。这样做的绊脚石是find的退出状态:如果成功遍历所有路径,则为0,否则为>。传递给find的表达式在退出代码中没有创建回显。
下面的示例测试目录是否有条目:
$ mkdir A
$ touch A/b
$ find A -maxdepth 0 -not -empty -print | head -n1 | grep -q . && echo 'not empty'
not empty
当A没有文件时,grep失败:
$ rm A/b
$ find A -maxdepth 0 -not -empty -print | head -n1 | grep -q . || echo 'empty'
empty
当A不存在时,grep再次失败,因为查找只打印到stderr:
$ rmdir A
$ find A -maxdepth 0 -not -empty -print | head -n1 | grep -q . && echo 'not empty' || echo 'empty'
find: 'A': No such file or directory
empty
用其他find表达式替换-not -empty,但如果-exec命令打印到stdout,请小心。在这种情况下,您可能需要使用grep来获得更具体的表达式。
这种方法在shell脚本中工作得很好。最初的问题是寻找glob xorg-x11-fonts*:
if find -maxdepth 0 -name 'xorg-x11-fonts*' -print | head -n1 | grep -q .
then
: the glob matched
else
: ...not
fi
注意,如果xorg-x11-fonts*没有匹配,或者find遇到错误,就会到达else-branched。使用$?来区分大小写。