On Linux, how do I selectively copy most – but not all – files from a directory (dir1) to another directory (dir2)?

I do not want to copy *.c and *.txt files to dir2.

The cp man page online cannot help me.

3 Answers 3


In addition to eboix's find command (which as it stands breaks on whitespace, I'll put a safer way or two at the end), you can use bash's extglob feature:

# turn extglob on
shopt -s extglob 
# move everything but the files matching the pattern
mv dir1/!(*.c) -t dir2
# If you want to exclude more patterns, add a pipe between them:
mv dir1/!(*.c|*.txt) -t dir2

See the bash man page for more you can do with extglob. Note that this is not recursive and so will only move files in dir1 directly, not subdirectories. The find method is recursive.

Safer find commands:

find dir1 ! -name '*.c' -print0 | xargs -0 mv -t dir2
find dir1 ! -name '*.c' -exec mv -t dir2 {} +

For more patterns, just add more ! -name statements:

find dir1 ! -name '*.c' ! -name '*.txt' -print0 | xargs -0 mv -t dir2
find dir1 ! -name '*.c' ! -name '*.txt' -exec mv -t dir2 {} +

Try this:

find ./ ! -name '*.c' | xargs -i cp {} dest_dir
  • This will break on whitespace, you should add -print0 / -0 or use -exec.
    – Kevin
    Commented Jan 9, 2012 at 2:53
  • Or don't use filenames with embedded blanks or special characters (frankly, a good idea!)
    – paulsm4
    Commented Jan 9, 2012 at 4:23
  • thanks, what if I want to avoid two or more files ? for example, '.c' or '.txt' ? Commented Jan 9, 2012 at 4:29
  • @user1002288 You add more ! -name ... statements, I've updated my answer to show this.
    – Kevin
    Commented Jan 9, 2012 at 14:36

You can use the below command from dir1:

cp ls|egrep -v .txt\|.c dir2

The part " ls|egrep -v .txt\|.c " will list files without .c and .txt in the name. cp will copy them to dir2

You must log in to answer this question.

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