Search code examples
bashparameter-passingls

How can I list a range of files in a Bash script?


I've got several files in a folder, with the following names:

FILE_201.txt
FILE_206.txt
FILE_215.txt
FILE_223.txt
FILE_229.txt
FILE_232.txt

I want to select files between two values (e.g. between "210" and "230"). From the command line, running

ls -1 FILE_{210..230}.txt

lists the desired files; no problem. However, if I run the following Bash script,

#!/bin/bash
ls -1 FILE_{$1..$2}.txt

passing 210 and 230 as arguments to it, it doesn't work.

What am I doing wrong?


Solution

  • The problem isn't about running the command at the command line or from a script. You can check that for yourself, by running the following at the command line:

    $ set 210 230 # assigns variables $1 and $2 the values "210" and "230", resp.
    $ ls -1 FILE_{$1..$2}.txt
    ls: FILE_{210..230}.txt: No such file or directory
    

    As you can see, you get the same error as the one raised by your script file. The problem is that brace expansion happens before variable expansion.

    In this case, by the time, $1 and $2 get expanded to 210 and 230, it's too late for the range to be interpreted as such; the { .. } part simply sticks around, without any special meaning attached to it.

    Anyway, using ls here is a bad idea, because you're going to get an error for each filename in the range that doesn't match an existing file. You'd be better off using a combination of a for loop and seq, as in this answer:

    #!/bin/bash
    
    # test.sh
    
    for n in $(seq $1 $2); do 
        f="FILE_$n.txt"
        if [ -e $f ]; then
            printf $s\\n "$f"
        fi
    done
    

    Example:

    $ touch FILE_209.txt
    $ touch FILE_213.txt
    $ touch FILE_224.txt
    $ touch FILE_232.txt
    $ bash test.sh 210 230
    FILE_213.txt
    FILE_224.txt