I'd like to find all files in a certain folder which have a filename of at least n
characters (extension included). Is there any way to achieve this with find
?
4 Answers
I think the simplest way is to use:
find . -name "??????????*"
where the number of ?
characters is equal with n
. Is simple because is hard to forget it.
But the nicest way is to use the -regex
option to find file names with n
or more characters:
find . -regextype posix-egrep -regex ".*[^/]{n}"
where n
should be a natural number (the minimum filename length).
See man find
fore more about.
-
When I give
find . -regextype posix-egrep -regex ".*[^/]{n}"
it says,find: ‘./lost+found’: Permission denied
. If I invoke the command withsudo
, it yields no results. Nov 28, 2019 at 5:44
You could use the find
command with a -regex
test
$ find /path/to/folder -regextype posix-basic -regex '.*/.\{5,\}'
or
$ find /path/to/folder -regextype posix-extended -regex '.*/.{5,}'
Note that -regex
is a path match rather than a file match - hence you need to match the leading .*/
as well, before the 5+ character filename
Alternatively, for a pure bash solution, you could enable extended shell globbing and then use the pattern !(@(?|??|???|????))
meaning 'anything that does not match one or two or three or four characters'
$ shopt -s extglob
$ ls -d /path/to/folder/!(@(?|??|???|????))
If you want to include subdirectories, you can enable the globstar
option as well and add a **
wildcard i.e.
$ shopt -s extglob globstar
$ ls -d /path/to/folder/**/!(@(?|??|???|????))
for example
$ ls -d **/!(@(?|??|???|????))
abcde abcdef abcdefg subdir subdir/abcde subdir/abcdef subdir/abcdefg
while the non inverted matches (files shorter than 5 characters) are
$ ls -d **/@(?|??|???|????)
a ab abc abcd subdir/a subdir/ab subdir/abc subdir/abcd
To unset the options afterwards, use
$ shopt -u extglob globstar
-
+1 Nice solutions, although they don't work for
n
as a minimum in general.– user54813Oct 19, 2013 at 18:56 -
Thank you @htor - on reflection, there doesn't seem to be any reason to prefer
!(@(?|??|???|????))
over @Radu Rădeanu's much simpler?????*
- perhaps I should delete the suggestion? Oct 19, 2013 at 19:08 -
When I first saw your answer, I just skipped because it seemed too complex. Then when no other answer was working, I came back to your answer and found that I actually did not need to read
Alternatively, for a pure bash
onwards. I think if you just omit rest of the answer, you will get better response. It is just my suggestion, may be wrong. Nov 28, 2019 at 5:49
Python approach:
#!/usr/bin/env python
from __future__ import print_function
import os,sys
def main():
treeroot = sys.argv[1]
base_len = int(sys.argv[2])
for dir,subdirs,files in os.walk(treeroot):
for f in files:
if len(f) >= base_len:
fullpath = os.path.abspath(os.path.join(dir,f))
print(fullpath)
if __name__ == '__main__' : main()
Usage is simple:
./find_files_len.py /path/to/top_directory/ minimal_length
For example:
./find_files_len.py /etc 5
That'll give us all files with basename of at least 5 characters , found recursively through /etc/
and all its subdirectories. Note that full path of the file will be printed to the command-line
You could loop over the list of files returned by find
and test the length of each file's basename:
min_fname() {
for path in $(find "$1" -type f); do
bn="${path##*/}"
if (( "${#bn}" >= $2 )); then
echo "$path"
fi
done
}
# usage: min_fname dir value
$ min_fname /tmp 5
$ min_fname /home/user 10
This function uses only find
and Bash builtin mechanisms, and no regex matching. Put this function definition in the ~/.bashrc
file to make the min_fname
command persistent between logins.