如果我想检查是否存在单个文件,我可以使用test -e filename
或[ -e filename ]
对其进行测试。
假设我有一个glob,我想知道是否存在名称与glob匹配的文件。 glob可以匹配0个文件(在这种情况下我不需要做任何事情),或者它可以匹配1个或多个文件(在这种情况下我需要做一些事情)。如何测试glob是否有匹配? (我不关心有多少匹配,如果我能用一个if
语句并且没有循环(仅仅因为我觉得最可读),这将是最好的。
(如果glob匹配多个文件,则test -e glob*
会失败。)
答案 0 :(得分:151)
nullglob shell选项确实是一种基础。
为了避免需要对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 操作,以便查找将在找到与搜索条件匹配的第一个文件后立即退出。在大量文件匹配的情况下,这应该比echo glob*
或ls glob*
快得多,并且它还避免了扩展命令行过度填充的可能性(某些shell具有4K长度限制)。
如果发现感觉过度杀戮并且可能匹配的文件数量很少,请使用stat:
if stat -t glob* >/dev/null 2>&1
then
echo found
else
echo not found
fi
答案 1 :(得分:139)
Bash 具体解决方案:
compgen -G "<glob-pattern>"
逃离模式,或者它会预先扩展为匹配项。
退出状态为:
stdout
是与
更新:请求的使用示例。
if compgen -G "/tmp/someFiles*" > /dev/null; then
echo "Some files exist."
fi
答案 2 :(得分:21)
#!/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
答案 3 :(得分:17)
我喜欢
exists() {
[ -e "$1" ]
}
if exists glob*; then
echo found
else
echo not found
fi
这既可读又有效(除非有大量文件)
主要的缺点是它比它看起来更微妙,我有时会觉得不得不添加一个长评论。
如果匹配,则"glob*"
由shell扩展,并且所有匹配都将传递给exists()
,"glob*"
将检查第一个匹配并忽略其余匹配。
如果没有匹配项,exists()
会传递给{{1}},并且发现它不存在。
编辑:可能存在误报,请参阅comment
答案 4 :(得分:6)
测试-e有一个不幸的警告,它认为破碎的符号链接不存在。所以你可能也想检查那些。
function globexists {
test -e "$1" -o -L "$1"
}
if globexists glob*; then
echo found
else
echo not found
fi
答案 5 :(得分:5)
如果你有globfail设置,你可以使用这个疯狂(你真的不应该)
shopt -s failglob # exit if * does not match
( : * ) && echo 0 || echo 1
或
q=( * ) && echo 0 || echo 1
答案 6 :(得分:4)
我还有另一个解决方案:
if [ "$(echo glob*)" != 'glob*' ]
这对我很有用。我想念一些角落案件吗?
答案 7 :(得分:3)
根据他的想法,简化MYYN的答案:
M=(*py)
if [ -e ${M[0]} ]; then
echo Found
else
echo Not Found
fi
答案 8 :(得分:3)
基于flabdablet's answer,对我来说,最简单的(不一定是最快的)只是使用 find 本身,同时在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
答案 9 :(得分:1)
在Bash中,你可以为一个数组进行glob;如果glob不匹配,则您的数组将包含与现有文件不对应的单个条目:
#!/bin/bash
shellglob='*.sh'
scripts=($shellglob)
if [ -e "${scripts[0]}" ]
then stat "${scripts[@]}"
fi
注意:如果您设置了nullglob
,scripts
将是一个空数组,您应该使用[ "${scripts[*]}" ]
或[ "${#scripts[*]}" != 0 ]
进行测试。如果您正在编写一个必须使用或不使用nullglob
的库,那么您需要
if [ "${scripts[*]}" ] && [ -e "${scripts[0]}" ]
这种方法的一个优点是,您可以拥有要使用的文件列表,而不必重复全局操作。
答案 10 :(得分:1)
我没有看到这个答案,所以我想我会把它放在那里:
set -- glob*
[ -f "$1" ] && echo "found $@"
答案 11 :(得分:1)
在bash中类似(测试文件包含pattern
):
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
更好:因为我们可以区分更多情况,并且更精确。
只能使用一个通配符*
答案 12 :(得分: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计算为空字符串。因此,echo命令的任何非空输出都表明glob匹配了什么。
答案 13 :(得分:0)
extglob
)解决方案:bash -c $'shopt -s extglob \n /bin/ls -1U <ext-glob-pattern>'
如果至少有一个匹配项,则退出状态为0,如果没有匹配项,则退出状态为非零(2)。 stdout
包含一个以换行符分隔的匹配文件列表(以及文件名中包含用引号引起来的空格)。
或者,略有不同:
bash -c $'shopt -s extglob \n compgen -G <ext-glob-pattern>'
与基于ls
的解决方案的区别:可能更快(未测量),输出中未引用空格的文件名,没有匹配项时退出代码1(不是2:耸肩:)。
没有匹配项:
$ bash -c $'shopt -s extglob \n /bin/ls -1U @(*.foo|*.bar)'; echo "exit status: $?"
/bin/ls: cannot access '@(*.foo|*.bar)': No such file or directory
exit status: 2
至少一场比赛:
$ bash -c $'shopt -s extglob \n /bin/ls -1U @(*.ts|*.mp4)'; echo "exit status: $?"
'video1 with spaces.mp4'
video2.mp4
video3.mp4
exit status: 0
ls
'退出代码行为(为efficiency添加-U
,为输出控制添加-1
)。extglob
(通常是不希望的)。$
前缀,以便解释\n
,以便扩展的glob模式与shopt -s extglob
不在同一行上,否则扩展的glob模式将是语法错误! 注释1:我之所以努力解决此问题,是因为其他答案中建议的compgen -G "<glob-pattern>"
方法似乎不适用于brace expansion;但是我需要一些更高级的环球功能。
注意2::扩展的glob语法的可爱资源:http://mywiki.wooledge.org/glob#extglob
答案 14 :(得分:0)
set -- glob*
if [ -f "$1" ]; then
echo "It matched"
fi
如果glob*
不匹配,则$1
将包含'glob*'
。测试-f "$1"
不正确,因为glob*
文件不存在。
这适用于sh及其派生词:ksh和bash。它不会创建任何子外壳。 $(..)
和`...`
命令创建一个子外壳;他们分叉了一个过程,因此比该解决方案要慢。
答案 15 :(得分:0)
#!/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
答案 16 :(得分:0)
流行的观点是 [ -f file* ]
不起作用。事实上,它确实有效,而且我个人认为它在某些情况下非常有用——当我想在特定位置捕获一个且只有一个文件的名称时。例如,名称中包含版本号的文件。考虑以下代码:
if [ -f "$ROOT"/lib64/libc-*.so ] ;then
LIBC=$(basename -- "$ROOT"/lib64/libc-*.so .so)
else
echo "libc ??" ; exit 1
fi
顺便说一句,shellcheck 看到这样的用法时会大喊大叫。 :-) 我希望他们能解决这个问题!
答案 17 :(得分:0)
[ls glob* 2>/dev/null | head -n 1
]&amp;&amp; echo true
答案 18 :(得分:0)
if ls -d $glob > /dev/null 2>&1; then
echo Found.
else
echo Not found.
fi
请注意,如果有很多匹配或文件访问速度很慢,这可能非常耗时。
答案 19 :(得分:-1)
ls | grep -q "glob.*"
不是最有效的解决方案(如果目录中有大量文件可能会变慢),但它简单易读,并且还具有正则表达式比普通版更强大的优势bash glob模式。
答案 20 :(得分:-1)
(ls glob* &>/dev/null && echo Files found) || echo No file found