Question

I have a folder with files named as file_1.ext...file_90.ext. I can list a range of them with the following command:

$ ls /home/rasoul/myfolder/file_{6..19}.ext

but when I want to use this command inside a bash script, it doesn't work. Here is a minimal example:

#!/bin/bash

DIR=$1
st=$2
ed=$3

FILES=`ls ${DIR}/file\_\{$st..$ed\}.ext`
for f in $FILES; do
  echo $f
done

running it as,

$ bash test_script.sh /home/rasoul/myfolder 6 19

outputs the following error message:

ls: cannot access /home/rasoul/myfolder/file_{6..19}.ext: No such file or directory
Was it helpful?

Solution

Brace expansion happens before variable expansion.

(Moreover, don't parse ls output.). You could instead say:

for f in $(seq $st $ed); do 
    echo "${DIR}/file_${f}.ext";
done

OTHER TIPS

BASH always does brace expansion before variable expansion which is why ls is looking for a file /home/rasoul/myfolder/file_{6..19}.ext.

I personally use seq when I need to expand a number range that has variables in it. You could also use eval with echo to accomplish the same thing:

eval echo {$st..$ed}

But even if you used seq in your script, ls would not iterate over your range without a loop. If you want to check if files in the range exist, I would also avoid using ls here as you will get errors for every file in the range that doesn't exist. BASH can check if a file exists using -e.

Here is a loop that would check if a file exists within the range between variables $st and $ed and print it if it does:

for n in $(seq $st $ed); do 
    f="${DIR}/file_$n.ext"
    if [ -e $f ]; then
        echo $f
    fi
done

The range pattern {A..B} does not accept variables for A or B. You need constants for them. A workaround might be to start a subshell like this:

RESULT=$(bash -c "ls {$a..$b}")

Numeric ranges have to be literal numbers, you can't put variables in there. To do it you need to use eval:

FILES=`eval "ls ${DIR}/file_{$st..$ed}.ext"`

Here's a transcript of my test (I tried it in bash 4.1.5 and 3.2.48).

imac:testdir $ touch file_{1..30}.ext
imac:testdir $ st=6
imac:testdir $ ed=20
imac:testdir $ DIR=.
imac:testdir $ FILES=`eval "ls ${DIR}/file_{$st..$ed}.ext"`
imac:testdir $ echo "$FILES"
./file_10.ext
./file_11.ext
./file_12.ext
./file_13.ext
./file_14.ext
./file_15.ext
./file_16.ext
./file_17.ext
./file_18.ext
./file_19.ext
./file_20.ext
./file_6.ext
./file_7.ext
./file_8.ext
./file_9.ext
imac:testdir $ 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top