Test whether a glob has any matches in bash

2019-01-01 15:03发布

If I want to check for the existence of a single file, I can test for it using test -e filename or [ -e filename ].

Supposing I have a glob and I want to know whether any files exist whose names match the glob. The glob can match 0 files (in which case I need to do nothing), or it can match 1 or more files (in which case I need to do something). How can I test whether a glob has any matches? (I don't care how many matches there are, and it would be best if I could do this with one if statement and no loops (simply because I find that most readable).

(test -e glob* fails if the glob matches more than one file.)

标签: bash glob
18条回答
何处买醉
2楼-- · 2019-01-01 15:11

Based on flabdablet's answer, for me it looks like easiest (not necessarily fastest) is just to use find itself, while leaving glob expansion on shell, like:

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

Or in if like:

if find $yourGlob -quit &> /dev/null; then
    echo "MATCH"
else
    echo "NOT-FOUND"
fi
查看更多
忆尘夕之涩
3楼-- · 2019-01-01 15:11

This abomination seems to work:

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

It probably requires bash, not sh.

This works because the nullglob option causes the glob to evaluate to an empty string if there are no matches. Thus any non-empty output from the echo command indicates that the glob matched something.

查看更多
低头抚发
4楼-- · 2019-01-01 15:13

If you have globfail set you can use this crazy ( which you really should not )

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

or

q=( * ) && echo 0 || echo 1
查看更多
情到深处是孤独
5楼-- · 2019-01-01 15:19

Bash specific solution:

compgen -G "<glob-pattern>"

Escape the pattern or it'll get pre-expanded into matches.

Exit status is:

  • 1 for no-match,
  • 0 for 'one or more matches'

stdout is a list of files matching the glob.
I think this is the best option in terms of conciseness and minimizing potential side effects.

UPDATE: Example usage requested.

if compgen -G "/tmp/someFiles*" > /dev/null; then
    echo "Some files exist."
fi
查看更多
墨雨无痕
6楼-- · 2019-01-01 15:20
set -- glob*
if [ -f "$1" ]; then
  echo "It matched"
fi

Explanation

When there isn't a match for glob*, then $1 will contain 'glob*'. The test -f "$1" won't be true because the glob* file doesn't exist.

Why this is better than alternatives

This works with sh and derivates: ksh and bash. It doesn't create any sub-shell. $(..) and `...` commands create a sub-shell; they fork a process, and therefore are slower than this solution.

查看更多
临风纵饮
7楼-- · 2019-01-01 15:20

ls | grep -q "glob.*"

Not the most efficient solution (if there's a ton of files in the directory it might be slowish), but it's simple, easy to read and also has the advantage that regexes are more powerful than plain bash glob patterns.

查看更多
登录 后发表回答