list files numbered in a specific range
I have a set of files in a directory numbered as follows:
file1.txt
file2.txt
...
file30.txt
...
Now, I'd like to run a command on a specific range of files, lets say 18 through 31.
So far I have used the following ways,
three arguments
command file1[8-9].txt file2[0-9].txt file3[0-1].txt
Now suppose I want every other number,
loop
for i in `jot - 18 31 2`; do echo file${i}.txt; done | xargs command
this seems like it's a more reliable loop (spaces work)
for i in `jot - 18 31 2`; do echo "\"file${i}.txt\" "; done | xargs command
but it seems like there should be a simpler way to do this. I am guessing the best solution is to create a bash function that will return the set of files to the command line. Then I could do something like,
command `filerange file 18 31`
Are there better ways or suggestions on doing this efficiently?
I apologize in advance if I missed this same question answered somewhere else
on the web or on superuser
.
Solution 1:
Try this:
for file in file{18..31}.txt
It's known as a "sequence expression" and it's part of Bash's brace expansion feature. It works in Bash 3 and 4.
The increment feature is new to Bash 4. You probably have Bash 3.x.
In Bash 4, you can do:
$ for i in {1..6..2}; do echo $i; done
1
3
5
But in Bash 3, you have to do this to get the same results:
$ for ((i=1; i<=6; i+=2)); do echo $i; done
The same form incrementing by one:
$ for ((i=1; i<=6; i++)); do echo $i; done
Any of the numbers can be variables or expressions. However, in a sequence expression the numbers have to be constants
Here is an example using that form on your files:
for ((i=18; i<=31; i++))
do
echo "file${i}.txt"
done
Another new feature of sequence expressions in Bash 4 is the ability to include leading zeros. This is useful if you want to create (and use) numbered files that can be properly sorted.
In Bash 4:
touch file{001..010}.txt
would create files named "file001.txt" through "file010.txt". Their names will sort in the expected order. Without the leading zeros, "file10.txt" would sort before "file1.txt".
To work with the files, you can use the same leading zero syntax:
for file in file{001..010}.txt; do echo "$file"; done
In Bash 3, if you need leading zeros, you need to pad the value yourself:
for i in {1..10}
do
printf -v i '%03d' $i
echo "file${i}.txt"
done
The printf
statement will prepend the value of i with leading zeros so the width is 3, for example ("4" becomes "004").
Edit:
Accommodating spaces in filenames is straightforward:
$ touch "space name "{008..018..3}" more spaces"
$ ls -l sp*
-rw-r--r-- 1 user group 0 2011-01-22 11:48 space name 000008 more spaces
-rw-r--r-- 1 user group 0 2011-01-22 11:48 space name 000011 more spaces
-rw-r--r-- 1 user group 0 2011-01-22 11:48 space name 000014 more spaces
-rw-r--r-- 1 user group 0 2011-01-22 11:48 space name 000017 more spaces
$ for f in "space name "{008..018..3}" more spaces"; do mv "$f" "${f}.txt"; done
$ ls -l sp*
-rw-r--r-- 1 user group 0 2011-01-22 11:48 space name 000008 more spaces.txt
-rw-r--r-- 1 user group 0 2011-01-22 11:48 space name 000011 more spaces.txt
-rw-r--r-- 1 user group 0 2011-01-22 11:48 space name 000014 more spaces.txt
-rw-r--r-- 1 user group 0 2011-01-22 11:48 space name 000017 more spaces.txt