145

I would like to copy all files out of a dir except for one named Default.png. It seems that there are a number of ways to do this. What seems the most effective to you?

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
Joe Cannatti
  • 4,989
  • 5
  • 38
  • 56

9 Answers9

188

Should be as follows:

cp -r !(Default.png) /dest

If copying to a folder nested in the current folder (called example in the case below) you need to omit that directory also:

cp -r !(Default.png|example) /example
Jonathan Holloway
  • 62,090
  • 32
  • 125
  • 150
  • 20
    This produces -bash: !: event not found – Joe Cannatti Aug 21 '09 at 18:46
  • Are you copying the files to a folder nested within the folder your copying from? – Jonathan Holloway Aug 21 '09 at 18:48
  • 55
    This requires `shopt -s extglob` to work, if it has been disabled. – Barry Kelly Aug 21 '09 at 18:52
  • 5
    It seems that OS X needs to use `shopt -s extglob` as described by @BarryKelly. With that, it works perfectly. – Kat Jul 08 '14 at 23:45
  • 1
    Years on Bash and didn't know about `!()`... Beautiful! For those that --like me-- feel it is time to study/review [bash](https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html), here are the relevant links related to this question/answer: [shopt/extglob](https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html) and [the pattern](https://www.gnu.org/software/bash/manual/html_node/Pattern-Matching.html#Pattern-Matching). – Brandt Nov 26 '19 at 13:45
  • Just because I didn't quite grasp, at first, how to use this: `cp -r $src_path/!($file) $dest_path` would be equivalent to `cp $src_path/* $dest_path/ --exclude $file` if cp had such an argument. – mazunki Jul 11 '20 at 21:01
96

rsync has been my cp/scp replacement for a long time:

rsync -av from/ to/ --exclude=Default.png

-a, --archive               archive mode; equals -rlptgoD (no -H,-A,-X)
-v, --verbose               increase verbosity
czerasz
  • 13,682
  • 9
  • 53
  • 63
matja
  • 4,014
  • 3
  • 23
  • 29
66

Simple, if src/ only contains files:

find src/ ! -name Default.png -exec cp -t dest/ {} +

If src/ has sub-directories, this omits them, but does copy files inside of them:

find src/ -type f ! -name Default.png -exec cp -t dest/ {} +

If src/ has sub-directories, this does not recurse into them:

find src/ -type f -maxdepth 1 ! -name Default.png -exec cp -t dest/ {} +
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • 5
    This turns out to be the best for me because it would appear that OS X ships without glob enabled. – Joe Cannatti Aug 21 '09 at 20:54
  • 6
    @Max `\;` executes the command once per file. `+` runs the command once and passes all of the file names to it at once (subject to the command line length limit). `+` is a bit more efficient in general. – John Kugelman Sep 22 '14 at 00:48
3
cp `ls | grep -v Default.png` destdir
Will Hartung
  • 115,893
  • 19
  • 128
  • 203
  • 6
    This is more likely to produce errors than do what you intend. – Dennis Williamson Aug 22 '09 at 01:40
  • ok @DennisWilliamson, can you explain why? – arthur.sw Mar 02 '21 at 16:17
  • 1
    @arthur.sw For one thing, it doesn't account for files with spaces in it. As with many things with the shell, there's a bunch of edge cases that fail. 95%+ of the time, this stuff just works. Just need to be conscious of the caveats. Spaces in file names jump working with the shell from trivial to painful. – Will Hartung Mar 02 '21 at 17:50
  • Another reason is that since there are no anchors in the regex and the dot isn't escaped it would also match a file named `myDefaultXpng.OLD` for example. – Dennis Williamson Jun 27 '22 at 13:11
1

I'd just do:

cp srcdir/* destdir/ ; rm destdir/Default.png

unless the files are big. Otherwise use e.g.

find srcdir -type f/ |grep -v Default.png$ |xargs -ILIST cp LIST destdir/
linkyndy
  • 17,038
  • 20
  • 114
  • 194
nos
  • 223,662
  • 58
  • 417
  • 506
  • 4
    The first command is not what the OP asked for. If `Default.png` exists in the two directories, it will replace the one in `destdir` by the one in `srcdir`, then delete the copied `Default.png`. Instead, the OP wants to keep the `Default.png` that already exists in `destdir`. – SnowFrog May 22 '17 at 11:34
  • 3
    how about default.png already exists in destdir? Your solutioun won't work. – Iman Mohamadi Jun 03 '18 at 08:10
1

Jan, 2022 Update:

This is the easiest way(It's not complicated).

First, make "temp" folder:

mkdir temp

Second, copy all files from your original folder to "temp" folder:

"-R" flag can copy exactly all files including "Symbolic Links"

cp -R originalFolder/. temp/

Third, remove "Default.png" from "temp" folder:

rm temp/Default.png

Finally, copy all files from "temp" folder to your destination folder:

cp -R temp/. destinationFolder/

In addition, this is the shortest way without "temp" folder:

cp -R originalFolder/!(Default.png) destinationFolder/
Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
0

Below script worked for me

cp -r `ls -A | grep -v 'skip folder/file name'` destination
monofal
  • 1,928
  • 1
  • 13
  • 15
-1
# chattr +i /files_to_exclude
# cp source destination
# chattr -i /files_to_exclude
-3

use the shell's expansion parameter with regex

cp /<path>/[^not_to_copy_file]* .

Everything will be copied except for the not_to_copy_file

-- if something is wrong with this. please Specify !

alex
  • 1
  • 3
    Welcome to SO. Unfortunately your answer is not correct. The bracket expresssion (`[...]`) contains a set of characters to match, while a leading `^` will cause a match of the complement of the listed characters. In the following example, neither file will be listed: `touch not_to_copy_file to_copy_file ; ls [^not_to_copy_file]*` because all filenames starting with any of the following characters will be excluded: `_cefilnopty`. – rtx13 Apr 02 '20 at 04:56