Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Suppose that I have a folder containing .txt, .pdf, and other files. I would like to list the "other" files (i.e., files not having the extensions .txt or .pdf). Do you have any advice on how to do this?

I know how to list files not having a given extension. For example, if I want to list all files except the .txt files, then either

find -not -iname "*.txt"


ls | grep -v '\.txt$' | column

seem to work. But, how can I list everything except .txt files or .pdf files? It seems that I need to use some sort of logical "or" in find or grep.

share|improve this question
Keep in mind that the behavior of ls vs find vs globbing may differ for hidden dotfiles. –  jw013 Sep 4 '12 at 19:32
Another thing to keep in mind: find will traverse subdirectories, like a recursive ls. Use -maxdepth 1 with find to get it to behave more like ls. –  jw013 Sep 4 '12 at 20:20
So no recursive, just list the files in current dir ? –  warl0ck Sep 5 '12 at 7:20

6 Answers 6

up vote 8 down vote accepted

Assuming one has an appropriate version of ls, this is possibly the simplest way:

ls -I "*.txt" -I "*.pdf"

If you want to iterate across all the subdirectories:

ls -I "*.txt" -I "*.pdf" -R
share|improve this answer
GNU ls options aren't portable. –  bahamat Sep 5 '12 at 20:45
ls doesn't really belong in portable scripts anyways, so I've been assuming the OP is asking about interactive use only. –  jw013 Sep 5 '12 at 20:53

With bash extended globbing (turn on with shopt -s extglob), the glob !(*.txt|*.pdf) should work. You can pass this glob directly to any command that takes file arguments, including but not limited to ls.

share|improve this answer
+1 but if you've subdirectories then their contents would be listed too; use -d to avoid that: ls -d !(*.txt|*.pdf) –  legends2k Nov 11 at 14:43

Find supports -o

find . ! '(' -name '*.txt' -o -name '*.pdf' ')'

You need the parenthesis to make the precedence right. Find does a lot of stuff; I suggest reading through its manpage.

You can also do an or in grep (but really, you should not parse the output of ls)

ls | grep -Ev '\.(txt|pdf)$' | column
share|improve this answer
Thanks! Why shouldn't I parse the output of ls? –  Andrew Sep 4 '12 at 19:36
@Andrew first, because its fragile (consider a file name with a newline in it—yes, that's a valid file name—find's -print0/-exec/-delete/etc. avoid that problem); second, because there is usually an easier way. –  derobert Sep 4 '12 at 19:38

In zsh with extendedglob:

print -rl -- *~*.(txt|pdf)


print -rl -- ^*.(txt|pdf)

Or with kshglob (yes, that is ksh globbing not "bash extended globbing"):

print -rl -- !(*.txt|*.pdf)

Remember though that those also exclude dot files.

ksh93 has the FIGNORE (mis)feature:

printf '%s\n' *
share|improve this answer

As suggested by derobert, your best bet is to use find. However, you can in fact use the result in a pipeline with other commands.

GNU (and some BSD's) find support the -print0 predicate which tells it to print the filename terminated by a NUL character, which character isn't allowed within a file name and guarantees there won't be a collision. Other commands can be instructed to use the NUL as their input delimiter.

The most important of which is GNU xargs, which runs the command you specify and passes to it the list of files as command line arguments. You want to run xargs -r0 in conjunction with find's -print0 For example:

find . -type f ! \( -name \*.pdf -o -name \*.txt \) -print0 | xargs -r0 ls -ld

This safely prints a long directory listing of all the pdf and txt files, including those with spaces or unprintable characters in the name.

You can also use it with GNU tar as follows:

tar -zcf myarchive.tar.gz --null --files-from <(
  find . -type f ! -name \*.tar.gz -print0)

This builds a tar.gz file of all the files whose names don't end in .tar.gz

rsync also accepts null-delimited files with the -0 parameter, as do several others. But xargs is the glue you'll usually use for this type of purpose. Either that or find's -exec feature.

share|improve this answer
find /path/to/directory '!' -name '*.pdf' '!' -name '*.txt'

This is equivalent to the command with the OR operator, because of the De Morgan's laws.

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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