I want to find some files, in a non GNU environment

  • in the current directory only
  • with extension *.ext1 and *.ext2,
  • but not name1.* or name2.*

The following command works, but may be not efficient, because the shell expands ./* and find can get a huge list of files and directories.

find ./* -prune \( -name '*ext1' -o -name '*ext2' \) -a ! \( -name 'name1*' -o -name 'name2*' \)


I'm working on AIX, there is no -maxdepth option.


With find:

find . ! -name . -prune \
    \( -name '*.ext1' -o -name '*.ext2' \) \
  ! \( -name 'name1.*' -o -name 'name2.*' \)

Using -prune is the standard equivalent of GNU's -maxdepth or of some BSD's -depth <n> (though those BSDs now also support -mindepth/-maxdepth à la GNU). Here it tells find not to descend in any directory except ..

the ! -name . makes it also exclude . from the selection, so ! -name . -prune is the standard equivalent of GNU's -mindepth 1 -maxdepth 1 or some BSDs' -depth 1. For GNU's -mindepth 1 (some BSDs' -depth -2), you'd write find . \( -name . -o -prune \).

With zsh, you can also make it:

setopt extendedglob
printf '%s\n' *.(ext1|ext2)~(name1|name2).*(D)

~ being the and-not operator, and (D) to include dot-files.

  • Thank you, this is the fastest solution indeed :) find . ! -name . -prune is the point! – Mattia72 Dec 9 '16 at 10:36

In your current directory you can use ls with grep (assuming your file names don't contain newline characters):

ls -a | grep -E '\.ext(1|2)$' | grep -vE '^name(1|2)\.'
  • 1
    Thanks, it works! It runs much faster as my solution with globbing. I've not enough reputation to vote it up :( – Mattia72 Dec 7 '16 at 8:23

"In the current directory only" you don't need to find files, you can simply list them (with the usual caveats about the possibility of encoutering bizarre file names, containing interesting characters):

ls -d *.ext1 *.ext2 2>/dev/null | grep -v '^\(name1\|name2\)\.'
  • Consider a huge directory with many files and folders... I would avoid shell globbing. – Mattia72 Dec 7 '16 at 8:03
  • Why is shell globbing less eficient that find? find has no special method of looking at file names. – AlexP Dec 7 '16 at 8:03
  • Ok, but the "transport" of a huge list of parameters between the shell and find takes time. – Mattia72 Dec 7 '16 at 8:16

Since you have bash available, you can use its extended pattern matching:

shopt -s extglob
files=( !(name1|name2).@(ext1|ext2) )

This says: all the files in the current directory that do not start with "name1" or "name2", followed by a period, followed by either "ext1" or "ext2".

For a sample run:

$ touch name1.ext1 name1.ext2 name2.ext1 name2.ext2 name3.ext1 name3.ext2 name3.ext3
$ files=( !(name1|name2).@(ext1|ext2) )
$ declare -p files
declare -a files='([0]="name3.ext1" [1]="name3.ext2")'

Note that if you have a simple filename like "name3.ext2", you have to choose where to put the period for the pattern matching -- either in "name3." or in ".ext2"; if you have longer filenames, such as "name3.intermediate.ext2", then you could use dots and a glob in the middle:

$ files=( !(name1|name2).*.@(ext1|ext2) )

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.