testingglob是否在bash中有任何匹配

如果我想检查单个文件的存在,我可以使用test -e filename[ -e filename ]进行test -e filename

假设我有一个glob,我想知道是否存在名称与glob匹配的文件。 glob可以匹配0个文件(在这种情况下,我不需要做任何事情),也可以匹配1个或多个文件(在这种情况下,我需要做些什么)。 我如何testingglob是否有任何匹配? (我不在乎有多less比赛,如果我可以用一个if语句和没有循环(简单地说是因为我觉得最可读)做到这一点是最好的。

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

 compgen -G "<glob-pattern>" 

退出模式,或者将其预先扩展为匹配。 退出状态为1表示不匹配,0表示“一个或多个匹配”。 stdout是匹配glob的文件列表。 我认为这是在简洁和减less潜在副作用方面最好的select。

更新 :请求使用示例。

 if compgen -G "/tmp/someFiles*" > /dev/null; then echo "Some files exist." fi 

nullglob shell选项确实是一种双重性(bashism)。

为了避免需要繁琐的保存和恢复nullglob状态,我只能在扩展glob的子shell中进行设置:

 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操作,以便find一旦find符合search条件的第一个文件就立即退出。 在大量文件匹配的情况下,这应该比echo glob*ls glob*运行得更快,同时也避免了扩展命令行的过度填充的可能性(一些shell有4K长度限制)。

如果find感觉像过度杀伤,可能匹配的文件数量很小,使用stat:

 if stat -t glob* >/dev/null 2>&1 then echo found else echo not found fi 
 #!/usr/bin/env bash # If it is set, then an unmatched glob is swept away entirely -- # replaced with a set of zero words -- # instead of remaining in place as a single word. shopt -s nullglob M=(*px) if [ "${#M[*]}" -ge 1 ]; then echo "${#M[*]} matches." else echo "No such files." fi 

我喜欢

 exists() { [ -e "$1" ] } if exists glob*; then echo found else echo not found fi 

这是可读和高效的(除非有大量的文件)。 主要缺点是它比看起来更微妙,有时候我不得不添加一个很长的评论。 如果匹配,则shell将扩展“glob *”,并将所有匹配项传递给exists(),它将检查第一个并忽略其余部分。 如果不匹配,则将“glob *”传递给exists(),并且在那里也不存在。

testing-e有不幸的警告,它认为断开的符号链接不存在。 所以你可能也想检查一下。

 function globexists { test -e "$1" -o -L "$1" } if globexists glob*; then echo found else echo not found fi 

我还有另一个解决scheme:

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

这对我来说很好。 有没有我想念的angular落案件?

为了简化MYYN的回答,基于他的想法:

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

基于flabdablet的答案 ,对我来说,看起来像最简单(不一定是最快)只是使用查找本身,而在shell上留下glob扩展,如:

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

或者if喜欢:

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

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

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

要么

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

这种可憎的行为似乎奏效:

 #!/usr/bin/env bash shopt -s nullglob if [ "`echo *py`" != "" ]; then echo "Glob matched" else echo "Glob did not match" fi 

这可能需要bash,而不是sh。

这是有效的,因为如果没有匹配项,nullglob选项会导致glob求值为空string。 因此,echo命令的任何非空输出都表示glob匹配了某个东西。

我没有看到这个答案,所以我想我会把它放在那里:

 set -- glob* [ -f "$1" ] && echo "found $@" 
 (ls glob* &>/dev/null && echo Files found) || echo No file found 
 if ls -d $glob > /dev/null 2>&1; then echo Found. else echo Not found. fi 

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

 #!/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 

ls | grep -q "glob.*"

不是最有效的解决scheme(如果目录中有很多文件可能会慢一点),但它很简单,易于阅读,并且还具有正则expression式比纯bash全局模式更强大的优势。

[ ls glob* 2>/dev/null | head -n 1 ls glob* 2>/dev/null | head -n 1 ] && echo true