How can I copy a directory without copying a specific file or subdirectory in terminal?

I have a directory main_dir which contains lots of files and 3 subdirectories (dir1 and dir2 and dir3). I want to copy it to another location without copying dir2 in one command. I searched the cp manual to see if this can be done somehow but I did not find the answer. My only solution was to copy the whole directory and then delete dir2 in the copied location.

cp -r main_dir ~/Documents/main_dir_copy
cd ~/Documents/main_dir_copy
rm -r dir2

Is there a way to do this without having to copy all the contents of dir2 and then delete it?


Solution 1:

In bash, you can use an extended glob to implement negation.

Given

$ tree main_dir
main_dir
├── dir1
│   ├── other file
│   └── somefile
├── dir2
│   ├── other file
│   └── somefile
├── dir3
│   ├── other file
│   └── somefile
└── file

3 directories, 7 files

then

shopt -s extglob
cp -r main_dir/!(dir2) main_dir_copy/

resulting in

$ tree main_dir_copy
main_dir_copy
├── dir1
│   ├── other file
│   └── somefile
├── dir3
│   ├── other file
│   └── somefile
└── file

2 directories, 5 files

Note that since this recursively copies the contents of main_dir (excluding the given dir2) rather than main_dir itself, the target directory main_dir_copy must already exist - if it doesn't, add mkdir main_dir_copy to the command sequence.

See also

  • How to exclude some files from filename expansion mechanism in bash?
  • Delete subdirectories leaving a given one