4

Situation 1

How do I copy /home/src/somedir to /dest/ such that the path always ends up as /dest/somedir, regardless of whether /dest/somedir already exists?

I want to avoid ending up with /dest/somedir/somedir.

Situation 2

How do I copy everything inside /home/src/somedir to /dest/ such that /dest/somedir isn't created and is ignored if it already exists?


Are there rules about the trailing slashes I can use? I thought ending with a trailing slash meant always copy the contents only but it still often goes wrong for me.

  • 1
    what specifically do you mean by "ignored"? do you want the copy to continue or to abort? cp -r /home/src/somedir /dest/ should address both situations, either creating or merging into the existing folder – Frank Thomas Dec 22 '15 at 17:58
  • Does it have to be with cp? There's probably a correct option to rsync that will do this. – Barmar Dec 25 '15 at 18:55
7

cp will always copy the file(s) at the start of the command to the file or directory at the end of the command. The slash doesn't really do much to the arguments, unless the argument is a symlink to a directory. Then having the slash will treat it like a directory while omitting the slash will copy the link itself.

Assuming you want recursively copy any subdirectories in your examples you'd do them like:

cp -r /home/src/somedir /dest

and

cp -r /home/src/somedir/* /dest

The first gets the directory /home/src/somedir and will copy that argument, the directory itself and all the contents of it, to the last arg, /dest. It will create the somedir directory in /dest if needed and use it if it already exists.

The second addes * to the end of the first argument, which the shell will expand to be every file that does not start with . in /home/src/somedir and will copy all of those files and directories to /dest without regard to what's already there (except some flags to cp will make it prompt to overwrite files that will have the same in in the destination as an existing file).

As the comments to this answer have pointed out, there are problems using * to grab all the files in the directory. One alternative would be to use tar to do the copy for you

tar -c -C /home/src/somedir . | tar -x -C /dest

this will create a tar file of somedir without the leading path by using -C to switch to that directory first. By default tar will print to stdout which we will then pipe to another tar to extract it switching into the desired /dest directory first. This will also preserve lots of file attributes, which cp can do as well.

| improve this answer | |
  • 2
    Worth noting that * wildcard expansion will fail if there are too many matches. I don't know the exact number, but the last time it failed for me, the directory contained around 100000 files/directories. – Aleks G Dec 22 '15 at 22:02
  • Good point, also if there are no files by default it will try to copy a file named * – Eric Renouf Dec 22 '15 at 22:11
  • Indeed, so in a production-level script you'd add all these checks. – Aleks G Dec 22 '15 at 22:16
  • Yep definitely want to avoid wildcard considering it doesn't copy hidden files and has issues in the way it expands in the shell. – Person Dec 23 '15 at 11:01
  • @AleksG and @Person given the observations of difficulties with globs I included an alternative that doesn't use cp but should accomplish the task – Eric Renouf Dec 23 '15 at 14:48
2

How do I copy /home/src/somedir to /dest/ such that the path always ends up as /dest/somedir, regardless of whether /dest/somedir already exists?

cp -rv /home/src/somedir /dest

We are copying «somedir» to «/dest», so we end up with «/dest/somedir»

How do I copy everything inside /home/src/somedir to /dest/ such that /dest/somedir isn't created and is ignored if it already exists?

cp -rv /home/src/somedir/* /dest

We are copying «all files in somedir» (somedir/*) to «/dest»

Caveat: somedir/* doesn't include hidden files (those beginning with a dot).

The final slashes don't affect the process. You may be confusing cp with rsync, where a trailing slash means “copy the contents, not the folder”.

| improve this answer | |
  • I think this answer is missing an explanation about using a trailing dot to achieve copying the files. – Person Dec 23 '15 at 14:50
1

On BSD systems, put a slash on the end of the source:

cp -R src/ dest

On GNU Linux systems, use the -T flag:

cp -rT src dest

note that

cp src/* dest

is to be avoided, partly because it ignores hidden dot files, and partly because glob expansion could exceed the limit.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.