Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Zsh: Test whether a file matching a pattern exists

Tags:

shell

zsh

I have a glob pattern PATTERN and would like to implement the following logic in Zsh:

if a file matching *PATTERN* exists, then
     do this-and-that
end

Note that I don't need to know, which files actually match the pattern; only the fact that there is some file (or directory) is relevant.

I couldn't find a clever way to do this with an if statement, so I implemented it using a "loop" which is executed at most once:

for f in *PATTERN*(N)
do
  this-and-that
  break
done

This works: If no entry matches PATTERN, the (N) causes an error message to be suppressed and the loop is skipped; otherwise, the loop body is executed once.

Question: Is there a way where I can achieve my goal with just a if, no loop?

like image 376
user1934428 Avatar asked Jan 06 '17 09:01

user1934428


2 Answers

Yes, there is in zsh. (setopt extendedglob required for the (#q…) form glob qualifier notation.)

if [[ -n *PATTERN*(#qN) ]]; then
    this-and-that
fi

There are some descriptions and a similar example in zsh's documents "CONDITIONAL EXPRESSIONS" and "Glob Qualifiers":

Filename generation is not performed on any form of argument to conditions. However, it can be forced in any case where normal shell expansion is valid and when the option EXTENDED_GLOB is in effect by using an explicit glob qualifier of the form (#q) at the end of the string. A normal glob qualifier expression may appear between the ‘q’ and the closing parenthesis; if none appears the expression has no effect beyond causing filename generation. The results of filename generation are joined together to form a single word, as with the results of other forms of expansion.

This special use of filename generation is only available with the [[ syntax. If the condition occurs within the [ or test builtin commands then globbing occurs instead as part of normal command line expansion before the condition is evaluated. In this case it may generate multiple words which are likely to confuse the syntax of the test command.

For example,

[[ -n file*(#qN) ]]

produces status zero if and only if there is at least one file in the current directory beginning with the string ‘file’. The globbing qualifier N ensures that the expression is empty if there is no matching file.

-- zshmisc(1): CONDITIONAL EXPRESSIONS

--

If the option EXTENDED_GLOB is set, a different syntax for glob qualifiers is available, namely ‘(#qx)’ where x is any of the same glob qualifiers used in the other format. The qualifiers must still appear at the end of the pattern. However, with this syntax multiple glob qualifiers may be chained together. They are treated as a logical AND of the individual sets of flags. Also, as the syntax is unambiguous, the expression will be treated as glob qualifiers just as long any parentheses contained within it are balanced; appearance of ‘|’, ‘(’ or ‘~’ does not negate the effect. Note that qualifiers will be recognised in this form even if a bare glob qualifier exists at the end of the pattern, for example ‘*(#q*)(.)’ will recognise executable regular files if both options are set; however, mixed syntax should probably be avoided for the sake of clarity. Note that within conditions using the ‘[[’ form the presence of a parenthesised expression (#q...) at the end of a string indicates that globbing should be performed; the expression may include glob qualifiers, but it is also valid if it is simply (#q). This does not apply to the right hand side of pattern match operators as the syntax already has special significance.

-- zshexpn(1): Expansion, Filename Generation, Glob Qualifiers

like image 73
hchbaw Avatar answered Nov 12 '22 12:11

hchbaw


one way you can do is, load the found files(filenames) in an array, and check the array length:

a=(*.txt)
echo ${#a}
like image 3
Kent Avatar answered Nov 12 '22 13:11

Kent