How to use 'cp' command to exclude a specific directory?

rsync is fast and easy:

rsync -av --progress sourcefolder /destinationfolder --exclude thefoldertoexclude

You can use --exclude multiples times.

rsync -av --progress sourcefolder /destinationfolder --exclude thefoldertoexclude --exclude anotherfoldertoexclude

Note that the dir thefoldertoexclude after --exclude option is relative to the sourcefolder, i.e., sourcefolder/thefoldertoexclude.

Also you can add -n for dry run to see what will be copied before performing real operation, and if everything is ok, remove -n from command line.


Well, if exclusion of certain filename patterns had to be performed by every unix-ish file utility (like cp, mv, rm, tar, rsync, scp, ...), an immense duplication of effort would occur. Instead, such things can be done as part of globbing, i.e. by your shell.

bash

man 1 bash, / extglob.

Example:

$ shopt -s extglob
$ echo images/*
images/004.bmp images/033.jpg images/1276338351183.jpg images/2252.png
$ echo images/!(*.jpg)
images/004.bmp images/2252.png

So you just put a pattern inside !(), and it negates the match. The pattern can be arbitrarily complex, starting from enumeration of individual paths (as Vanwaril shows in another answer): !(filename1|path2|etc3), to regex-like things with stars and character classes. Refer to the manpage for details.

zsh

man 1 zshexpn, / filename generation.

You can do setopt KSH_GLOB and use bash-like patterns. Or,

% setopt EXTENDED_GLOB
% echo images/*
images/004.bmp images/033.jpg images/1276338351183.jpg images/2252.png
% echo images/*~*.jpg
images/004.bmp images/2252.png

So x~y matches pattern x, but excludes pattern y. Once again, for full details refer to manpage.


fishnew!

The fish shell has a much prettier answer to this:

🐟 cp (string match -v '*.excluded.names' -- srcdir/*) destdir

Bonus pro-tip

Type cp *, hit CtrlX* and just see what happens. it's not harmful I promise