Reputation: 2854
You'd think I could find an answer to this already somewhere, but I am struggling to do so. I want to find some log files with names like
myfile_3.log
however I only want to find the ones with numbers in a certain range. I tried things like this:
find <path> -name myfile_{0..67}.log #error: find: paths must precede expression
find <path> -name myfile_[0-67].log #only return 0-7, not 67
find <path> -name myfile_[0,67].log #only returns 0,6,7
find <path> -name myfile_*([0,67]).log # returns only 0,6,7,60,66,67,70,76,77
Any other ideas?
Upvotes: 5
Views: 9344
Reputation: 13249
If you want to match an integer range using regular expression, use the option -regex
in the your find
command.
For example to match all files from 0 to 67, use this:
find <path> -regextype egrep -regex '.*file([0-5][0-9]|6[0-7])\.txt'
There are 2 parts in the regex:
[0-5][0-9]
matches the range 0-596[0-7]
matches the range 60-67Note the option -regextype egrep
to have extended regular expression.
Note also the option -regex
matches the whole filename, including path, that's the reason of .*
at the beginning of the regex.
Upvotes: 6
Reputation: 207445
You can do this simply and concisely, but admittedly not very efficiently, with GNU Parallel:
parallel find . -name "*file{}.txt" ::: {0..67}
In case, you are wondering why I say it is not that efficient, it is because it starts 68 parallel instances of find
- each looking for a different number in the filename... but that may be ok.
Upvotes: 3
Reputation: 8064
One possibility is to build up the range from several ranges that can be matched by glob patterns. For example:
find . -name 'myfile_[0-9].log' -o -name 'myfile_[1-5][0-9].log' -o -name 'myfile_6[0-7].log'
Upvotes: 0
Reputation: 24982
The following will find all files named myfile_X.log
- whereby the X
part is a digit ranging from 0-67.
find <path> -type f | grep -E "/myfile_([0-9]|[0-5][0-9]|6[0-7])\.log$"
Explanation:
-type f
finds files whose type is file.
|
pipes the filepath(s) to grep
for filtering.
grep -E "/myfile_([0-9]|[0-5][0-9]|6[0-7])\.log$"
performs an extended (-E
) regexp to find the last part of the path (i.e. the filename) which:
myfile_
.log
Alternatively, as suggested by @ghoti in the comments, you can utilize the -regex
option in the find
command instead of piping to grep
. For example:
find -E <path> -type f -regex ".*/myfile_([0-9]|[0-5][0-9]|6[0-7])\.log$"
Note: The regexp is very similar to the previous grep
example shown previously. However, it begins with .*/
to match all parts of the filepath up to and including the final forward slash. For some reason, unknown to me, the .*/
part is not necessary with grep
1.
Footnotes:
1If any readers know why the ERE utilized with find's -regex
option requires the initial .*
and the same ERE with grep
does not - then please leave a comment. You'll make me sleep better at night ;)
Upvotes: 1
Reputation: 5762
You cannot represent a general range with a regular expression, although you can craft a regex for a specific range. Better use find to get files with a number and filter the output with another tool that perform the range checking, like awk.
START=0
END=67
while IFS= read -r -d '' file
do
N=$(echo "$file" | sed 's/file_\([0-9]\+\).log/\1/')
if [ "$N" -ge "$START" -a "$N" -le "$END" ]
then
echo "$file"
fi
done < <(find <path> -name "myfile_*.log" -print0)
In that script, you perform a find
of all the files that have the desired pattern, then you loop through the found files and sed
is used to capture the number in the filename. Finally, you compare that number with your range limits. If the comparisons succeed, the file is printed.
There are many other answers that give you a regex for the specific range in the example, but they are not general. Any of them allows for easy modification of the range involved.
Upvotes: -1