How to use 'cp' command to exclude a specific directory?
Solution 1
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.
Solution 2
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
Solution 3
Why use rsync
when you can do:
find . -type f -not -iname '*/not-from-here/*' -exec cp '{}' '/dest/{}' ';'
This assumes the target directory structure being the same as the source's.
Solution 4
cp -r `ls -A | grep -v "c"` $HOME/
Solution 5
The easiest way I found, where you can copy all the files excluding files and folders just by adding their names in the parentheses:
shopt -s extglob
cp -r !(Filename1 | FoldernameX | Filename2) Dest/
David Liu
Updated on February 01, 2022Comments
-
David Liu over 2 years
I want to copy all files in a directory except some files in a specific sub-directory. I have noticed that
cp
command didn't have the--exclude
option. So, how can I achieve this? -
Paulo Scardine over 13 yearswatch out for directory entries containing spaces.
-
Shawn Chin over 13 yearsYou can skip the extra
ls
and simply docp !(file1|file1) dest
. -
James Murty about 12 yearsI think you need the
-path
argument to test path hierarchies, not -iname -
Matthew Wilcoxson over 11 yearsAnd you'll also need a semi-colon at the end:
find . -type f -not -path '*/not-from-here/*' -exec cp '{}' '/dest/{}' \;
-
Linus Kleen over 11 years@MatthewWilcoxson Thanks Matthew, go ahead an edit my answer.
-
Matthew Wilcoxson over 11 yearsAgreed, you can't beat the simplicity and power of
--exclude
-
Matthew Wilcoxson over 11 yearsWow, it won't let me: "Edits must be at least 6 characters" !
-
Linus Kleen over 11 years@MatthewWilcoxson Meh. Those restrictions will be lifted, as soon as you gain a little more rep. I edited the answer accordingly. Thanks again!
-
Beebee almost 11 yearsis the
thefoldertoexclude
relative to thesourcefolder
or the current working dir? thanks -
orkoden over 10 yearsIt's relative to the source folder. This will exclude the folder source/.git from being copied. rsync -r --exclude '.git' source target
-
Xavi Montero over 10 yearsMaybe I'm wrong but I think it's a good practice to add "switches" before "parameters". Also the man page of rsync reports --exclude usable as with the "=" syntax or without. So to standarize across operating systems, I'd use
rsync -av --progress --exclude="thefoldertoexclude" sourcefolder /destinationfolder
- anyway upvote for the rsync instead of the find, as you can easily use absolute paths for the source while in the find it's trickier as it uses the{}
in the dst. -
Linus Kleen over 10 yearsWhy, thank you, @Henning for pointing that out. Although this answer is now more than three years old, it never occurred to me that
rsync
might actually be a shorter command. Wait. No. It did. That's why I mentioned it. Now it's up to you to supply that answer right here. Just because mine is the accepted answer doesn't mean yours could outscore it. Go for it. -
geneorama about 10 yearsDoesn't work for me. I get
-bash: !: event not found
-
AmokHuginnsson almost 10 yearsI am sorry but rsync is not installed by default on any system I know of, tar OTOH is.
-
imkost over 9 yearsshopt -s extglob (execute this to enable ! in cp, rm and others)
-
ulidtko almost 9 years@MikhailGolubtsov perhaps that's because globbing is not recursive and works one level at a time. Edited out. P.S: it works in
zsh
though. -
Osman Mamun almost 9 yearsCan I use it in case of file transfer across machines (like scp)?
-
thebugfinder almost 9 years@XaviMontero definitely not, as you add many of those switches, it will get lost what is the actual folder being copied. imaging having, 5 exclude switches. Some args are good to have them at the end, i think
-
tomekwi almost 9 yearsNot pretty maybe – but this is the only option I’ve found here which works with
cp
and a standard POSIX shell likesh
. -
Masker over 8 yearsI think slash at wrong place,
rsync -av --progress sourcefolder/ destinationfolder --exclude thefoldertoexclude
-
sobi3ch over 8 years@mamun Of course e.g. from remote server to local machine:
$ rsync [email protected]:/var/www/mypage /var/www/mylocalpage/
or from local to remote$ rsync /var/www/mylocalpage/ [email protected]:/var/www/mypage
-
sobi3ch over 8 yearsUnfortunately I found that
rsync
are ~4x slower thencp
command :( at least on my VM even when I'm including big.git
directory incp
task and excluding inrsync
. -
LAL over 8 yearsDo not use -laR. it add string that interfere with cp.
cp $(ls folder/!exclude_folder0|exclude_folder1)) dest
-
Paulo Neves over 7 yearsUnfortunately rsync cannot coppy as symlink :(
-
tibbus about 7 yearsThis command is purely magic, it doesn't overwrite the unchanged files, it also shows you the time and the transfer speed, also shows you which file where copied only the different ones !!
-
atwellpub almost 7 yearsWorked for me in Windows 10 .sh
-
Kennet Celeste over 6 yearshow can I exclude multiple folders/files with this? thanks
-
Oleg Neumyvakin about 6 years@Yugi you can add --exclude multiple times for another folders
-
taffit about 6 yearsNice pro-tip! This way you can remove single items easily. Thanks a lot!
-
Reishin almost 6 years@Henning why not
rsync
? Coz it may be not present in the system! whilefind
,cp
is always on their places. Or you from kind of guys, who installed 2gigs of stuff to do simple things? -
xuhdev over 5 yearsWhat if
/dest/
do not have required directory structure? -
Linus Kleen over 5 years@xuhdev Hence the disclaimer in the answer. It only works when the target directory structure is the same as the source's.
-
ElectRocnic about 5 yearsMade a shell function which simplifies the usage for custom source path and exclusion of just one file or directory:
# $1 = source path # $2 = destination path # $3 = filter copy_from_source_to_destination_except_filter() { cp -r $(ls -A $1 | grep -v -w $3 | awk -v path=$1 '{printf "%s/%s ", path, $1}') $2 }
-
Sérgio about 5 yearsa simple solution that take cares of special characters and white spaces
-
Sérgio about 5 yearsfails with directories with spaces
-
Rockallite over 4 yearsBTW, to turn off extended pattern matching features in Bash, run
setopt -u extglob
. -
reducing activity over 4 yearsWhat is the difference/improvement compared to the top answer?
-
reducing activity over 4 yearsWhat is the difference/improvement compared to the top answer?
-
reducing activity over 4 yearsThanks for explaining parameters, unlike the current top answer!
-
Robert Talada about 4 yearsThis answer is dramatically underrated. This is the most compatible, easiest to read and easy to understand answer. Kudos, I don't know why I didn't think of it.
-
kungfooman about 4 yearsThanks @RobertTalada, how far will the answer go from now? ️🌈
-
ayorgo over 3 years"... an immense duplication of effort..." shouldn't it be just a one-liner: exclude paths from the list that match a regex? How the file manipulating utilities like
cp
don't support this most simple and straightforward use case out of the box is beyond me. Thanks for the tip though! -
ulidtko over 3 years@ayorgo well yes it "should" — but in C, a oneliner can't do much: multiply some ints and maybe move a pointer, that's it. Even ignoring the source level, regex matching in C involves additional library dependency and additional machine code output — now multiply this by the number of commands, and you've got nontrivial (unbounded?..) overhead. At least that's my understanding why it was "refactored" to the shell; I can totally relate to the subpar UI aspect of it, but hopefully you can also see the technical justification now. Best wishes!
-
mbomb007 over 3 years@geneorama This happens if history substitution is enabled. serverfault.com/a/208414/352016
-
Arch Stanton over 3 years@Sérgio I haven't tested it but
cp -r "$(ls -A | grep -v "c")" $HOME/
should work. The command in the answer fails because therecp
operates on the output ofls -A | grep -v "c"
, which is unquoted and therefore breaks on spaces."$(…)"
is the same as"`…`"
but easier on the eyes. -
qräbnö over 3 yearsMy fix for that - somewhere below: stackoverflow.com/a/65485164/1707015
-
DarkTrick over 3 years@orkoden Here on Ubuntu exclude works relative to the current working dir (which is really unintuitive)
-
Hódos Gábor over 3 years@XaviMontero and if you want to exclude multiple folders you can use rsync like this rsync -av --progress --exclude={"thefoldertoexclude","anotherfolder","folder2"} sourcefolder /destinationfolder
-
Xavi Montero over 3 yearsAhh good to know @HódosGábor. I always gave multiple
--exclude
options by typing them all. Nice compact format! -
ddzzbbwwmm about 3 yearshow about multiple folder to exclude?
-
Abdull about 3 yearsGave it a try. Current version of your answer creates in the first step directories. Because this step currently contains
-not -path '*/not-from-here/*'
, it will create directory./not-from-here
. Probably, this is not intended. Therefore, for the first step (directory creation), you probably want-not -path '*/log'
instead. -
Kasun Siyambalapitiya about 3 years@hank what is the use of
-a
in above as per the man page it is for archiving or for appending data onto shorter files? -
PJ Brunet about 3 yearsThe nice thing about tar, you can use exclude.tag files to ignore directories stackoverflow.com/a/13280610/722796 also gnu.org/software/tar/manual/html_node/exclude.html
-
Robino almost 3 yearsObvious drawback is that you might be avoiding copying something because it's too big.
-
gekkedev almost 3 years@reducingactivity less obsolete flags
-
Fahad Munir almost 3 years
--exclude /node_modules/
will exclude node_modules anywhere in the source tree. So powerful while copying a bunch of JavaScript/Node.js project folders. -
Hawkeye Parker almost 3 yearsI feel like the '-a' in the first answer is better than plain old -r: explainshell.com/explain?cmd=rsync+-a
-
Dalbergia almost 3 years@ddzzbbwwmm You probably figured it out by now, but for posterity's sake: you can add multiple
--exclude
flags, like:--exclude 'foo' --exclude 'bar'
-
Goran B. almost 3 years@reducingactivity nothing much but simple to digest as the expression is shorter, just my personal preference
-
t7e about 2 yearsWhat if I want to exclude folders as well?
-
t7e about 2 yearsNice tip, but it does not work in sh.
-
t7e about 2 yearswhat about POSIX sh?
-
ulidtko about 2 years@t7e in that case, I'm afraid, you're restricted to
find ... | xargs
.