Is there a way of getting the names of all the files matched by a pattern entered as argument in bash?

85 Views Asked by At

I'm writing a bash script where I need to get the names of all the files that match a certain pattern I give as argument.For example if I have the files 'test1.txt', 'test2.txt' and 'test3.py' and run my command as :

my_command *.txt

I want to get the names 'test1.txt' and 'test2.txt' yet when I do this I only seem to get the one that is first alphabetically.

I'm sorry if this is an asked and answered question or a noobish one but I'm very new to bash scripting.

I've tried ls $1, echo $1, echo "$1" and finally

for var in $1;
do echo $var
done

and all those methods have given me only the alphabetically first file

4

There are 4 best solutions below

0
Cyrus On

I suggest to replace $1 in your code with "$@" to get all arguments to my_command.

1
mtth On

Disabling pathname expansion for a shell in which the script my_command
is executed could be another solution to the one posted by Cyrus. Please see:
man bash and then setting attributes of shell with set -f or set -o noglob commands.

edit: my answer uses the fact that subshell in bash does not by default inherit options changed in its parent shell so the following commands solve the problem as well:

$ touch test{1,2,3}.txt                                                         
$ ls *.txt                                                                      
test1.txt  test2.txt  test3.txt                                                 
$ cat > my_command                                                              
#!/bin/sh                                                                       
for var in $1;                                                                  
do echo $var                                                                    
done                                                                            
$ chmod +x my_command                                                           
$ ./my_command *.txt                                                            
test1.txt                                                                       
$ set -f                                                                        
$ ./my_command *.txt                                                            
test1.txt                                                                       
test2.txt                                                                       
test3.txt                                                                       
$
1
amphetamachine On

In your script:

for var; do
    echo "$var"
done

for var; is shorthand for for var in "$@";.

0
John Bollinger On

You have a misunderstanding. Here ...

my_command *.txt

... the pattern is not provided as an argument to the command, except (probably) if it does not match anything. The shell expands the pattern before executing the command, and the results are provided to the command as separate arguments.

I only seem to get the one that is first alphabetically.

That's because you're looking only at $1, the first argument. The command will receive each matching filename as a separate argument. You can use $@ and $* to access the whole argument list (but for most purposes you probably want the former), or you can shift them into the first position one at a time until you've processed them all. Or the arguments are the default data iterated by a for loop if nothing else is specified.

Examples:

# rejects the case where there were no matches, resulting in the pattern itself
# being presented as the argument
if [[ -e "$1" ]]; then
    echo "$@"

    for arg; do
        printf '%s\n' "$arg"
    done

    while [[ $# -gt 0 ]]; do
        printf '%s\n' "$1"
        shift
    done
fi