Wildcard match?

  • Follow


If I have a file.txt in a directory, I can echo "hello" as follows:

if [ -a file.txt ];
then
echo "hello";
fi

But how can I use a wildcard in this situation, such as *.txt and echo if 
there is one or more matches? For example:

if [ -a *.txt ];
then
echo "hello";
fi

Wtih the above, although if there's no match there's no error or echo, 
which is correct, but if there is one match the error "[: file.txt: binary 
operator expected" occurs, or if there are more matches the error "[: too 
many arguments" occurs. How can this type of wildcard check done in bash?

Many thanks,
Tuxedo

0
Reply Tuxedo 2/24/2011 11:24:23 PM

Tuxedo <tuxedo@mailinator.com> writes:

> If I have a file.txt in a directory, I can echo "hello" as follows:
>
> if [ -a file.txt ];
> then
> echo "hello";
> fi
>
> But how can I use a wildcard in this situation, such as *.txt and echo if 
> there is one or more matches? For example:
>
> if [ -a *.txt ];
> then
> echo "hello";
> fi
>
> Wtih the above, although if there's no match there's no error or echo, 
> which is correct, but if there is one match the error "[: file.txt: binary 
> operator expected" occurs, or if there are more matches the error "[: too 
> many arguments" occurs. How can this type of wildcard check done in
> bash?

I think you want to test if a glob does or does not match some files.
First off, forget -a: it is useful only between tests.  You could use -n
to test is a single string is not empty.  To do that you need to get the
result of the glob quoted.  There are lots of ways to do this but these
spring to mind:

  FILELIST=*.txt
  if [ -n "$FILELIST" ]

or

  if [ -n "$(printf %s *.txt)" ]

You can also use a bash array:

  FILELIST=(*.txt)
  if [ ${#FILELIST[*]} -gt 0 ]
  
If the number of matches might be very large you are probably better off
avoiding "*.txt" altogether.  'find' could be used but that's a little
more complex and may be overkill though it does free you from
any problems to do with shell glob options:

  if [ -n "$(find . -maxdepth 1 -name '*.c' -print -quit)" ]

-- 
Ben.
0
Reply Ben 2/25/2011 12:45:09 AM


On 2011-02-24, Tuxedo wrote:
> If I have a file.txt in a directory, I can echo "hello" as follows:
>
> if [ -a file.txt ];
> then
> echo "hello";
> fi
>
> But how can I use a wildcard in this situation, such as *.txt and echo if 
> there is one or more matches? For example:
>
> if [ -a *.txt ];
> then
> echo "hello";
> fi
>
> Wtih the above, although if there's no match there's no error or echo, 
> which is correct, but if there is one match the error "[: file.txt: binary 
> operator expected" occurs, or if there are more matches the error "[: too 
> many arguments" occurs. How can this type of wildcard check done in bash?

is_file ()
{
    for f in "$@"
    do
        [ -f "$f" ] && return
    done
    return 1
}

if is_file *.txt
then
   echo Hello
fi

-- 
   Chris F.A. Johnson, author           <http://shell.cfajohnson.com/>
   ===================================================================
   Shell Scripting Recipes: A Problem-Solution Approach (2005, Apress)
   Pro Bash Programming: Scripting the GNU/Linux Shell (2009, Apress)

0
Reply Chris 2/25/2011 1:31:50 AM

Chris F.A. Johnson wrote:

[...]

> is_file ()
> {
>     for f in "$@"
>     do
>         [ -f "$f" ] && return
>     done
>     return 1
> }
> 
> if is_file *.txt
> then
>    echo Hello
> fi
> 

Thanks for posting this as well as to Ben for posting the ideas in the 
prior post. All have been tested and work fine!

Tuxedo
0
Reply Tuxedo 2/25/2011 5:16:21 PM

On 25.02.2011 00:24, Tuxedo wrote:
> If I have a file.txt in a directory, I can echo "hello" as follows:
> 
> if [ -a file.txt ];
> then
> echo "hello";
> fi
> 
> But how can I use a wildcard in this situation, such as *.txt and echo if 
> there is one or more matches? For example:
> 
> if [ -a *.txt ];
> then
> echo "hello";
> fi
> 
> Wtih the above, although if there's no match there's no error or echo, 
> which is correct, but if there is one match the error "[: file.txt: binary 
> operator expected" occurs, or if there are more matches the error "[: too 
> many arguments" occurs. How can this type of wildcard check done in bash?

Other options...

: *.txt
[ -e "$_" ] && echo Hello


set -- *.txt
[ -e "$1" ] && echo Hello


Janis

> 
> Many thanks,
> Tuxedo
> 

0
Reply Janis 2/25/2011 8:50:14 PM

2011-02-25, 21:50(+01), Janis Papanagnou:
[...]
> set -- *.txt
> [ -e "$1" ] && echo Hello
[...]

$ ln -s /xxx a.txt
$ touch b.txt
$ set -- *.txt
$ [ -e "$1" ] || echo no
no


You may want:

set -- [*].txt *.txt

if [ "$1$2" != "[*].txt*.txt" ]; then
  shift
  echo There are txt files:
  printf '  %s\n' "$@"
else
  echo >&2 "There doesn't appear to be any txt file here"
fi

-- 
Stephane
0
Reply Stephane 2/25/2011 9:07:19 PM

On 25.02.2011 00:24, Tuxedo wrote:
> If I have a file.txt in a directory, I can echo "hello" as follows:
>
> if [ -a file.txt ];
> then
> echo "hello";
> fi
>
> But how can I use a wildcard in this situation, such as *.txt and echo if
> there is one or more matches? For example:
>
> if [ -a *.txt ];
> then
> echo "hello";
> fi
>
> Wtih the above, although if there's no match there's no error or echo,
> which is correct, but if there is one match the error "[: file.txt: binary
> operator expected" occurs, or if there are more matches the error "[: too
> many arguments" occurs. How can this type of wildcard check done in bash?


in bash you can set the shell option `failglob', so bash will return an 
error if the glob does not match anything:

shopt -s failglob
(for x in *.txt; do echo hello; break; done 2>/dev/null) || echo no 
files match

Best regards

Mart
0
Reply Mart 2/26/2011 10:03:35 AM

On Feb 26, 2:07=A0am, Stephane CHAZELAS <stephane_chaze...@yahoo.fr>
wrote:
> 2011-02-25, 21:50(+01), Janis Papanagnou:
> [...]> set -- *.txt
> > [ -e "$1" ] && echo Hello
>
> [...]
>
> $ ln -s /xxx a.txt
> $ touch b.txt
> $ set -- *.txt
> $ [ -e "$1" ] || echo no
> no
>
> You may want:
>
> set -- [*].txt *.txt
>
> if [ "$1$2" !=3D "[*].txt*.txt" ]; then
> =A0 shift
> =A0 echo There are txt files:
> =A0 printf ' =A0%s\n' "$@"
> else
> =A0 echo >&2 "There doesn't appear to be any txt file here"
> fi
>
> --
> Stephane


Stephane,
Can you please explain how the above code works?
-- Rakesh
0
Reply Rakesh 2/28/2011 5:02:20 PM

2011-02-28, 09:02(-08), Rakesh Sharma:
[...]
>> set -- [*].txt *.txt
>>
>> if [ "$1$2" != "[*].txt*.txt" ]; then
>>   shift
>>   echo There are txt files:
>>   printf '  %s\n' "$@"
>> else
>>   echo >&2 "There doesn't appear to be any txt file here"
>> fi
[...]
> Stephane,
> Can you please explain how the above code works?
[...]

That trick was introduced here by Laura Fairhead some time ago.

In

set -- *.txt

*.txt would expand to "*.txt" if there's no txt file (well, if
no non-hidden txt file can be found in the current directory),
so you may think of doing:

if [ "$1" = "*.txt" ]; then echo "there's no txt file"

The problem is that *.txt also expands to "*.txt" if there's one
txt file called "*.txt". To differentiate that case, we use
another pattern: [*].txt that also matches the "*.txt" file.

If there's no txt file, "[*].txt *.txt" will expand to "[*].txt
*.txt", if there's a file called "*.txt", it will expand
to "*.txt whatever", if there's no file called "*.txt", but a
whatever.txt file it will expand to "[*].txt whatever.txt",
"whatever" not being "*".

-- 
Stephane
0
Reply Stephane 2/28/2011 8:44:55 PM

8 Replies
514 Views

(page loaded in 0.12 seconds)

Similiar Articles:













7/20/2012 9:45:20 AM


Reply: