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 a --exclude option. So, how can I achieve this?
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
Link to manual, search for 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
Link to manual, section "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
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.
cp -r `ls -A | grep -v "c"` $HOME/
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/
Expanding on mvds’s comment, this works for me
cd dotfiles
tar -c --exclude .git --exclude README . | tar -x -C ~/dotfiles2
It's relative to the source directory.
This will exclude the directory source/.git from being copied.
rsync -r --exclude '.git' source target
I assume you're using bash or dash. Would this work?
shopt -s extglob # sets extended pattern matching options in the bash shell
cp $(ls -laR !(subdir/file1|file2|subdir2/file3)) destination
Doing an ls excluding the files you don't want, and using that as the first argument for cp
rsync
rsync -r --verbose --exclude 'exclude_pattern' ./* /to/where/
and first try it with -n option to see what is going to be copied
Another simpler option is to install and use rsync which has an --exclude-dir option, and can be used for both local and remote files.
This is a modification of Linus Kleen's answer. His answer didn't work for me because there would be a . added in front of the file path which cp doesn't like (the path would look like source/.destination/file).
This command worked for me:
find . -type f -not -path '*/exlude-path/*' -exec cp --parents '{}' '/destination/' \;
the --parents command preserves the directory structure.
mv tobecopied/tobeexcluded .
cp -r tobecopied dest/
mv tobeexcluded tobecopied/
Just move it temporally into a hidden directory (and rename it after, if wanted).
mkdir .hiddendir
cp * .hiddendir -R
mv .hiddendir realdirname
rsync is actually quite tricky. have to do multiple tests to make it work.
Let's say you want to copy /var/www/html to /var/www/dev but need to exclude /var/www/html/site/video/ directory maybe due to its size. The command would be:
rsync -av --exclude 'sites/video' /var/www/html/ /var/www/dev
Some caveat:
- The last slash
/in the source is needed, otherwise it will also copy the source directory rather than its content and becomes/var/www/dev/html/xxxx, which maybe is not what you want. The the
--excludepath is relative to the source directly. Even if you put full absolute path, it will not work.-vis for verbose,-ais for archive mode which means you want recursion and want to preserve almost everything.
One way would be to use find -0 with -prune to find all the files and directories you want to move, then use xargs -0 to copy each one.
cp -rv `ls -A | grep -vE "dirToExclude|targetDir"` targetDir
Edit: forgot to exclude the target path as well (otherwise it would recursively copy).
I use a "do while" loop to read the output of the find command. In this example, I am matching (rather than excluding) certain patterns since there are a more limited number of pattern matches that I want than that I don't want. You could reverse the logic with a -not in front of the -iname flags:
find . -type f -iname "*.flac" -o -print0 -iname "*.mp3" -print0 -o -iname "*.wav" -print0 -o -iname "*.aac" -print0 -o -iname "*.wma" -print0 | while read -d $'\0' file; do cp -ruv "$file" "/media/wd/network_sync/music/$file"; done
I use the above to copy all music type files that are newer on my server than the files on a Western Digital TV Live Hub that I have mounted at /media/wd. I use the above because I have a lot of DVD files, mpegs, etc. that I want to exclude AND because for some reason rsync looks like it is copying, but after I look at the wd device, the files are not there despite no errors during the rsync with this command:
rsync -av --progress --exclude=*.VOB --exclude=*.avi --exclude=*.mkv --exclude=*.ts --exclude=*.mpg --exclude=*.iso --exclude=*ar --exclude=*.vob --exclude=*.BUP --exclude=*.cdi --exclude=*.ISO --exclude=*.shn --exclude=*.MPG --exclude=*.AVI --exclude=*.DAT --exclude=*.img --exclude=*.nrg --exclude=*.cdr --exclude=*.bin --exclude=*.MOV --exclude=*.goutputs* --exclude=*.flv --exclude=*.mov --exclude=*.m2ts --exclude=*.cdg --exclude=*.IFO --exclude=*.asf --exclude=*.ite /media/2TB\ Data/data/music/* /media/wd/network_sync/music/
ls -I "filename1" -I "filename2" | xargs cp -rf -t destdir
The first part ls all the files but hidden specific files with flag -I. The output of ls is used as standard input for the second part. xargs build and execute command cp -rf -t destdir from standard input. the flag -r means copy directories recursively, -f means copy files forcibly which will overwrite the files in the destdir, -t specify the destination directory copy to.
来源:https://stackoverflow.com/questions/4585929/how-to-use-cp-command-to-exclude-a-specific-directory