Let's say I have a directory with files a1, a2, a3, b1, b2, b3. I only want to match files that start with a but don't contain 3. I tried ls -I "*3" *a* but it returns a1 a2 a3, even though I don't want it to match a3. Is this possible with ls?

  • interesting diverse set of answers here, but an explanation of why ls -I '*3' a* fails would be edifying. and/or why is the shell's globbed list not being subsequently filtered by the ignore switch to ls? Oct 21, 2015 at 20:53
  • The man page says about the -I option: do not list implied entries matching shell PATTERN, however it doesn't explain what is meant by implied, but I'm guessing it only applies to files that ls gets by glob expansions - and ls doesn't expand the a*, the shell does that. Oct 24, 2015 at 1:09

4 Answers 4



shopt -s extglob  
ls a!(*3*)
  • shopt -s extglob activates extended globbing.
  • a matches the starting a
  • !() negates the match inside the ()...
    • *3* which is 3 and anything before or after it.

$ touch 1 2 3 a1 a2 a3 b1 b2 b3 aa1 aa2 aa3 a2a a3a
$ ls a!(*3*)
a1  a2  a2a  aa1  aa2
  • 1
    FYI, requires set -s extglob
    – Brian
    Oct 21, 2015 at 19:31
  • @Brian Yea, just noticed^^
    – chaos
    Oct 21, 2015 at 19:33

Existing answers well state the best way to do this with globs; I'll include this because in most cases, find is a better option if you want to do scripting or further processing:

$ find . -maxdepth 1 -name 'a*' -not -name '*3*'

You can feed the answer to xargs for easy actions, or to a while read loop for more complicated things.


An easy way is

  • to list all files that match a*
  • then delete all lines containing a 3

The UNIX command is

ls -1 a* | grep -v 3

ls -1 shows one file per line.

grep normally finds lines that match a pattern but with -v this behaviour is inverted, i.e. grep finds line that don't match that pattern.

  • 2
    Hi Peter! It would be best to explain, in as much detail as is relevant, how your solution works.
    – dhag
    Oct 21, 2015 at 19:35
  • 2
    Parsing ls is not a goob idea: mywiki.wooledge.org/ParsingLs
    – chaos
    Oct 21, 2015 at 19:38

With zsh, using the ~ glob operator:

setopt extendedglob
print -rl -- a*~*3*

With gnu ls you could use two --ignore options:

ls -I '[^a]*' -I '*3*'

the 1st ignores all file names that don't start with a and the 2nd ignores file names that contain 3

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.