测试一个glob是否在bash中有任何匹配

Test whether a glob has any matches in bash

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

假设我有一个glob,我想知道是否存在任何名称与glob匹配的文件。glob可以匹配0个文件(在这种情况下,我不需要做任何事情),或者它可以匹配1个或多个文件(在这种情况下,我需要做一些事情)。如何测试一个球是否有任何匹配项?(我不在乎有多少个匹配项,如果我能用一个if语句,而不使用循环(仅仅是因为我发现这是最易读的),那就更好了。

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


事实上这是一nullglob壳的bashism选项。

为避免繁琐的需要保存和恢复状态的nullglob,我只把它填满,扩大在全球的内幕:

1
2
3
4
5
6
if test -n"$(shopt -s nullglob; echo glob*)"
then
    echo found
else
    echo not found
fi

为更好的可移植性和更灵活的通配符查找,使用:

1
2
3
4
5
6
if test -n"$(find . -maxdepth 1 -name 'glob*' -print -quit)"
then
    echo found
else
    echo not found
fi

显的行为是用于印刷的退出,而不是默认的"打印"这样的隐式的动作将退出尽快找到匹配的文件,它的第一搜索准则。在许多文件的运行更快的比赛,这应该不太echo glob*ls glob*也和它的扩展的可能性,avoids overstuffing(去壳,有一个命令行长度限制,4K的)。

如果找到感觉。样和数量匹配的文件可能是小的,使用的统计:

1
2
3
4
5
6
if stat -t glob* >/dev/null 2>&1
then
    echo found
else
    echo not found
fi


Bash specific solution:

1
compgen -G"<glob-pattern>"

逃亡的模式或它会对比赛有预扩增。

退出状态是:

  • 1是在比赛。
  • 如果一个或更多的比赛。"

stdout是匹配的文件列表生成。我认为这是最好的选择而言conciseness和减少潜在的副作用。

更新:使用要求的例子。

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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/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


我喜欢

1
2
3
4
5
6
7
8
9
exists() {
    [ -e"$1" ]
}

if exists glob*; then
    echo found
else
    echo not found
fi

这是一个可读的和有效的(除非有这巨大的数量的文件)。的主要缺点是,它是更大的比长的文字,我有时感觉到龙compelled添加评论。如果有一个匹配,"glob*"是由外壳和扩展到所有的比赛都是通过检查一个exists()第一,休息和忽视。如果没有匹配,是通过对"glob*"exists()和发现存在或不存在。

编辑:有可能是假阳性,见评论


我有一个解决方案:一个是美国

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

本厂是nicely我。有一些案件的一角吗?


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

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

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


myyn到简化的基于点的答案,他的理念:

1
2
3
4
5
6
M=(*py)
if [ -e ${M[0]} ]; then
  echo Found
else
  echo Not Found
fi


基于flabdablet的答案,它看起来像是我easiest(并不一定是最快的),只是为了找到本身的使用,而离开地球展开在线壳样:

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

或在if样:

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


我没有看到这个回答,所以我想我把它有。

1
2
set -- glob*
[ -f"$1" ] && echo"found $@"

这似乎令人厌恶的工作。

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

它可能需要打,不显示。

本厂nullglob期权的原因。因为在一个空字符串来评价,如果有在比赛中。因此,任何非空输出命令是从回波信号生成表示匹配的东西。


在派对上,你可以去到一个数组的函数;如果不匹配,您将输入数组包含单是不是对应到一个现有的文件。

1
2
3
4
5
6
7
8
9
#!/bin/bash

shellglob='*.sh'

scripts=($shellglob)

if [ -e"${scripts[0]}" ]
then stat"${scripts[@]}"
fi

注意:如果你有一scriptsnullglob集,将空数组,你应该测试与["${scripts[*]}" ]["${#scripts[*]}" != 0 ]或相反。如果你的写作是必须与图书馆工作nullglob或没有,你会想

1
if ["${scripts[*]}" ] && [ -e"${scripts[0]}" ]

这种方法的优势是,然后你有你的工作列表的文件要用的,而不是由一对重复的操作。


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

解释

如果没有与glob*匹配,那么$1将包含'glob*'。由于glob*文件不存在,因此测试-f"$1"将不为真。

为什么这比其他选择更好

这适用于sh和派生词:ksh和bash。它不会创建任何子shell。$(..)`...`命令创建一个子shell;它们分叉一个进程,因此比这个解决方案慢。


] [ ls glob* 2>/dev/null | head -n 1Echo &;&;真正的


1
2
3
4
5
6
7
8
9
10
11
12
13
#!/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


1
2
3
4
5
if ls -d $glob > /dev/null 2>&1; then
  echo Found.
else
  echo Not found.
fi

请注意,这可以产生超的球队比赛,如果有很多文件或访问是慢的。


ls | grep -q"glob.*"

不是最有效的解决方案(如果有)的文件在目录中,它可能是slowish),但它的简单,容易阅读,也有更多的优点,比普通攻击是强大的regexes glob模式。


1
(ls glob* &>/dev/null && echo Files found) || echo No file found