- Copy folder recursively, excluding some folders
- 9 Answers 9
- How do I create a copy of a directory in Unix/Linux? [closed]
- 3 Answers 3
- Copy all files in a directory to a local subdirectory in linux
- 3 Answers 3
- Copy via find -exec:
- Copy with extglob:
- Copy without extglob:
- How to copy files from the folder without the folder itself
- 3 Answers 3
Copy folder recursively, excluding some folders
I am trying to write a simple bash script that will copy the entire contents of a folder including hidden files and folders into another folder, but I want to exclude certain specific folders. How could I achieve this?
I imagine something like find . -name * piped to grep /v «exclude-pattern» to filter the ones you don’t want and then piped to cp to do the copy.
This should probably go to super user. The command you’re looking for is xargs. You could also do something like two tar’s connected by a pipe.
Maybe its late and it doesnt answer the question accurately but here’s a tip: If you want to exclude only immediate children of the directory you could take advantage of bash pattern matching, e.g. cp -R !(dir1|dir2) path/to/destination
Note that the !(dir1|dir2) pattern requires extglob to be turned on ( shopt -s extglob to turn it on).
9 Answers 9
rsync -av --exclude='path1/to/exclude' --exclude='path2/to/exclude' source destination
Note that using source and source/ are different. A trailing slash means to copy the contents of the folder source into destination . Without the trailing slash, it means copy the folder source into destination .
Alternatively, if you have lots of directories (or files) to exclude, you can use —exclude-from=FILE , where FILE is the name of a file containing files or directories to exclude.
—exclude may also contain wildcards, such as —exclude=*/.svn*
@AmokHuginnsson — What systems are you using? Rsync is included by default in all mainstream Linux distros I know of, including RHEL, CentOS, Debian, and Ubuntu, and I believe it’s in FreeBSD as well.
For RHEL derived distros: yum install rsync, or on Debian-based releases: apt-get install rsync . Unless you’re building your server from absolute base on your own hardware, this is a non-issue. rsync is installed by default on my Amazon EC2 boxes, as well and my boxes from ZeroLag and RackSpace.
Use tar along with a pipe.
cd /source_directory tar cf - --exclude=dir_to_exclude . | (cd /destination && tar xvf - )
You can even use this technique across ssh.
This approach unnecessarily first tars the target source (and exludes particular directories in the archive) and then untars it at the target. Not recommended!
@Waldheri you are wrong. This is the best solution. It does exactly what OP requested and it works on default install of most of the *nix like OSes. Taring and untaring is done on the fly with no file system artefact (in memory), cost of this tar+untar is negligible.
This is perfect when rsync is not available in your container and you don’t want to bother with installing it.
rsync went unavailable for us. So i updated the above tar a bit and this is what i came up with. tar -cf — —exclude=’./folder’ —exclude=’./file.tar’ ./source_directory | tar -xf — -C ./destination_directory
You can use find with the -prune option.
cd /source-dir find . -name .snapshot -prune -o \( \! -name *~ -print0 \)| cpio -pmd0 /dest-dir This command copies the contents of /source-dir to /dest-dir, but omits files and directories named .snapshot (and anything in them). It also omits files or directories whose name ends in ~, but not their con‐ tents. The construct -prune -o \( . -print0 \) is quite common. The idea here is that the expression before -prune matches things which are to be pruned. However, the -prune action itself returns true, so the following -o ensures that the right hand side is evaluated only for those directories which didn't get pruned (the contents of the pruned directories are not even visited, so their contents are irrelevant). The expression on the right hand side of the -o is in parentheses only for clarity. It emphasises that the -print0 action takes place only for things that didn't have -prune applied to them. Because the default `and' condition between tests binds more tightly than -o, this is the default anyway, but the parentheses help to show what is going on.
How do I create a copy of a directory in Unix/Linux? [closed]
I want to recursively create a copy of a directory and all its contents (e.g. files and subdirectories).
3 Answers 3
The option you’re looking for is -R .
cp -R path_to_source path_to_destination/
- If destination doesn’t exist, it will be created.
- -R means copy directories recursively . You can also use -r since it’s case-insensitive.
- To copy everything inside the source folder (symlinks, hidden files) without copying the source folder itself use -a flag along with trailing /. in the source (as per @muni764 ‘s / @Anton Krug ‘s comment):
cp -a path_to_source/. path_to_destination/
i wonder why this exact command in dockerfile copies all source directory files into destination, instead of copying just whole directory.
I believe the ‘/’ on the end makes a difference and that might account for your experience. If the source includes the trailing slash it will copy what is in the directory only. If it does not include the trailing slash, it will copy the directory as well and then the contents inside of it. My memory is this behavior varies by command and maybe event by OS a bit. Here’s a reference with more info.
I would say if you don’t want to include the source and you want to make sure everything is copied (symlinks, hidden files) without copying the source parent folder is to use -ra source/. destination. This will make sure the content of the folder is copied, but not the parent folder itself, which is sometimes handy. And the difference is the /.
Note the importance of «Slash dot» on your source in cp -r src/. dest I know it is mentioned but I still seem to miss it every time.
You are looking for the cp command. You need to change directories so that you are outside of the directory you are trying to copy.
If the directory you’re copying is called dir1 and you want to copy it to your /home/Pictures folder:
Linux is case-sensitive and also needs the / after each directory to know that it isn’t a file. ~ is a special character in the terminal that automatically evaluates to the current user’s home directory. If you need to know what directory you are in, use the command pwd .
When you don’t know how to use a Linux command, there is a manual page that you can refer to by typing:
Also, to auto complete long file paths when typing in the terminal, you can hit Tab after you’ve started typing the path and you will either be presented with choices, or it will insert the remaining part of the path.
There is an important distinction between Linux and Unix in the answer because for Linux (GNU and BusyBox) -R , -r , and —recursive are all equivalent, as mentioned in this answer. For portability, i.e. POSIX compliance, you would want to use -R because of some implementation-dependent differences with -r . It’s important to read the man pages to know any idiosyncrasies that may arise (this is a good use case to show why POSIX standards are useful).
Copy all files in a directory to a local subdirectory in linux
I’d like to make a copy of all the existing files and directories located in this directory in new_subdir . How can I accomplish this via the linux terminal?
3 Answers 3
This is an old question, but none of the answers seem to work (they cause the destination folder to be copied recursively into itself), so I figured I’d offer up some working examples:
Copy via find -exec:
find . ! -regex ‘.*/new_subdir’ ! -regex ‘.’ -exec cp -r ‘<>‘ new_subdir \;
This code uses regex to find all files and directories (in the current directory) which are not new_subdir and copies them into new_subdir. The ! -regex ‘.’ bit is in there to keep the current directory itself from being included. Using find is the most powerful technique I know, but it’s long-winded and a bit confusing at times.
Copy with extglob:
cp -r !(new_subdir) new_subdir
If you have extglob enabled for your bash terminal (which is probably the case), then you can use ! to copy all things in the current directory which are not new_subdir into new_subdir.
Copy without extglob:
mv * new_subdir ; cp -r new_subdir/* .
If you don’t have extglob and find doesn’t appeal to you and you really want to do something hacky, you can move all of the files into the subdirectory, then recursively copy them back to the original directory. Unlike cp which copies the destination folder into itself, mv just throws an error when it tries to move the destination folder inside of itself. (But it successfully moves every other file and folder.)
How to copy files from the folder without the folder itself
I’m trying to copy files and subfolders from A folder without the A itself. For instance, A folder contains next:
| file1.txt | file2.txt | subfolder1
sudo cp -r /home/username/A/ /usr/lib/B/
3 Answers 3
advanced cp
cp -r /home/username/A/. /usr/lib/B/
This is especially great because it works no matter whether the target directory already exists.
shell globbing
If there are not too many objects in the directory then you can use shell globbing:
mkdir -p /usr/lib/B/ shopt -s dotglob cp -r /home/username/A/* /usr/lib/B/
rsync -a /home/username/A/ /usr/lib/B/
The / at the end of the source path is important; works no matter whether the target directory already exists.
mkdir -p /usr/lib/B/ find /home/username/A/ -mindepth 1 -maxdepth 1 -exec cp -r -t /usr/lib/B/ <> +
or if you don’t need empty subdirectories:
find /home/username/A/ -mindepth 1 -type f -exec cp --parents -t /usr/lib/B/ <> +
The first one works just fine! Any ideas why home/username/A/* (with star-symbol) doesn’t make sense? Variant with dot at the end helped me, thanks!
shopt is bash specific. With zsh , use *(D) . with ksh93 , FIGNORE=’@(.|..)’ . cp -t is GNU specific. The find one will not work properly as it will copy both A/ and its content (including subdirs) several times.
You also want -maxdepth 1 ( -mindepth and -maxdepth being GNU extensions now also supported by a few others. Portably find . /. ! -name . -prune -exec . )
If on a GNU system, from man cp :
-T, --no-target-directory treat DEST as a normal file
This allows you to write cp -rT /home/username/A/ /usr/lib/B/ to do exactly the right thing.
This should be the accepted answer, this is proper than shell globbing or using something else than cp . But that’s true that -T won’t work with a non-GNU cp .
Nice, but this answer (nor the man page) doesn’t explain why treating DEST as normal file results in this wanted behaviour.
Tell cp to copy the directory’s contents and not the directory itself:
sudo cp -r /home/username/A/* /usr/lib/B/
@pushandpop well, yes. That’s the target you had in your question so I assumed it was a directory. You need to create the target before attempting to copy files into it.
@Veverke please post a new question if you need more details and show us the exact commands you used. That said, if you run cp -r foo/* bar one of two things will happen: if bar does not exist, or if it exists but is not a directory, you will get an error message. If it does exist and is a directory, then all non-hidden files/dirs from foo will be copied into bar . If you run cp -r foo/ bar , then if bar exists and is a directory, that will copy the directory foo and place it as a subdirectory of bar . If bar does not exist or is not a directory, you will get an error.