So, you can use the * as a wild card for all files when using cp within context of a directory. Is there a way to copy all files except x file?
7 Answers
Rsync handles this nicely.
Example copy all: rsync -aP /folder1/* /folder/2
Example copy all with exclusion: rsync -aP --exclude=x /folder1/* /folder2/
The -aP switch:
a: Similar tocp -a, recursive, etc.P: Shows progress, a nice feature of rsync.
-
7And see this answer for a short guide to common rsync exclusion lists.Gilles 'SO- stop being evil'– Gilles 'SO- stop being evil'2012-06-26 22:27:26 +00:00Commented Jun 26, 2012 at 22:27
-
2On darwin/MacOS, use
-rPinstead of-aPif you want to recurse.-ais for archiving. Not sure if this changed or if it's just different on MacOS.jpoveda– jpoveda2017-06-02 23:30:07 +00:00Commented Jun 2, 2017 at 23:30 -
1
rsyncdoes have the option to make it recursive. Example:rsync --recursive -P --exclude=x /folder1/* /folder2/. (Tested only on Ubuntu)n1k31t4– n1k31t42018-04-09 10:45:05 +00:00Commented Apr 9, 2018 at 10:45
In bash you can use extglob:
$ shopt -s extglob # to enable extglob
$ cp !(b*) new_dir/
where !(b*) exclude all b* files.
You can later disable extglob with
$ shopt -u extglob
-
Do you know if there's something equivalent for the tcsh shell?Levon– Levon2012-06-27 01:33:30 +00:00Commented Jun 27, 2012 at 1:33
-
Unfortunately I don't. Seems like
findis the only way intcsh:find . -maxdepth 1 ! -name "exclude*" -exec cp -t destination {} \+rush– rush2012-06-27 05:25:29 +00:00Commented Jun 27, 2012 at 5:25
This isn't a feature of cp, it's a feature of your shell (it expands the * to mean all non-dot files), so the answer depends on which shell you're using. For example, zsh supports this syntax:
$ cp ^x /path/to/destination
Where ^x means "all files except x"
You can also combine selection and de-selection patterns, e.g. to copy all wav files except those containing xyz, you can use:
cp *.wav~*xyz*
-
1Any comments on
bash?Chad Harrison– Chad Harrison2012-06-26 19:59:57 +00:00Commented Jun 26, 2012 at 19:59 -
@hydroparadise I don't know much about bash, but this answer seems to cover itMichael Mrozek– Michael Mrozek2012-06-26 20:00:35 +00:00Commented Jun 26, 2012 at 20:00
-
What about tcsh? Anyone know?Levon– Levon2012-06-27 01:32:47 +00:00Commented Jun 27, 2012 at 1:32
If you want to copy everything in a folder (including subfolders) to a particular sub-directory:
cp -R $(ls | grep -v '^subdir$') subdir/
Works with sh, bash, zsh (at least).
-
2Convince me this isn't the same intention as
cp -R * subdir/Chris Davies– Chris Davies2015-10-28 23:51:48 +00:00Commented Oct 28, 2015 at 23:51 -
2If you use that command "cp -R * subdir/", bash/zsh tried to copy 'subdir' recurvively. You end up with an error: "name too long (not copied)".user2707671– user27076712015-12-23 10:48:34 +00:00Commented Dec 23, 2015 at 10:48
-
2Good point. Your suggestion attempts to avoid the warning from
cp(not frombash/sh), "cp: cannot copy a directory, ‘subdir’, into itself, ‘subdir/subdir’". The copy does complete correctly, though. Unfortunately your variant breaks with any filename containing a space or shell-sensitive punctuation. See unix.stackexchange.com/q/128985/135943Chris Davies– Chris Davies2015-12-23 11:41:45 +00:00Commented Dec 23, 2015 at 11:41
Could also be done in plain old (portable/compatible) bourne shell in a variety of ways with standard tools in a lot less elegant ways than using advanced shell globbing or commands with built-in-exclusion options.
If there are not too many files (and not with names including spaces and/or linebreaks), this could be a way:
cp `ls | egrep -v '^excludename$'` destdir/.
Sure, bash and GNU tools are great and powerful, but they're still not always available. If you intend to put it in a portable script, I would recommend find as in the comment by Rush.
-
2I find that the last part of your answer just distracts from the topic at hand. Besides, "Unix" isn't the gold standard anymore (if it ever were). It just isn't that relevant if something is "Unix" or not anymore, despite the title of this site being "Unix and Linux".Alexander– Alexander2012-06-27 08:44:12 +00:00Commented Jun 27, 2012 at 8:44
-
2OK. I moved the comment to here instead: Unix is not GNU. I agree that the "unixness" of things is not very interesting, but I still believe in portability and knowing a bit about your history.MattBianco– MattBianco2012-06-27 08:55:44 +00:00Commented Jun 27, 2012 at 8:55
-
Fully agree with you there.Alexander– Alexander2012-06-27 08:57:10 +00:00Commented Jun 27, 2012 at 8:57
The best and simple way is using find. Go to the source directory. Then use the following commands.
find . ! -name "*.log" | xargs -i cp -r {} ~/destination_dir
This copies all files except "*.log" files.
-
1Note that find recursively searches all subdirectories by default, so using
cp -ris causing to recurse twice on each file. Either usefindwith-maxdepth 0or remove-rfrom thecp.not2savvy– not2savvy2021-07-23 08:14:26 +00:00Commented Jul 23, 2021 at 8:14 -
Suggestion to exclude both the
-roncpas well as to limit find result to files only:find . -type f ! -name "*.log" | xargs -i cp {} ~/destination_dirMikeOnline– MikeOnline2023-11-14 17:26:41 +00:00Commented Nov 14, 2023 at 17:26
extglob is the best way so far I guess.
Another way is using
cp $(ls --ignore=x) subdir/
-
2This will break given any form of special characters whatsoever in the filenames. (Spaces, newlines,
$, etc.) Never parse the output ofls. unix.stackexchange.com/q/128985/135943Wildcard– Wildcard2015-12-04 06:14:28 +00:00Commented Dec 4, 2015 at 6:14