7

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 4

9

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.

1
  • When I give find . -regextype posix-egrep -regex ".*[^/]{n}" it says, find: ‘./lost+found’: Permission denied. If I invoke the command with sudo, it yields no results. Nov 28, 2019 at 5:44
5

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
3
  • +1 Nice solutions, although they don't work for n as a minimum in general.
    – user54813
    Oct 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
1

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

0

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.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .