Among the tons of cp questions I have not found anything about this difference in behaviour (tested on Ubuntu 18.04). Sorry for the lost post, but the setting is a bit complex.
Case 1: This is the expected behaviour
Given the following folder
source
file1.cpp
file2.cpp
after running this script
#!/bin/bash
cp -r source/ target/
I do get this result
source # same as above, plus a copy in "target"
file1.cpp
file2.cpp
target
file1.cpp
file2.cpp
Case 2: Using the same script, source folder exists and is empty in the target folder
Here there is one additional, empty folder
source
file1.cpp
file2.cpp
target
source
and run the same script
#!/bin/bash
cp -r source/ target/
which gives me a different, undesired result
source # same as above, plus a copy in "target"
file1.cpp
file2.cpp
target
source
file1.cpp
file2.cpp
Normal Solution for Case1 and Case2
cp -r source/ target/ # works only for Case 1
cp -r source/* target/ # works only for Case 2
Used in the wrong case, one will cause an error, the other yield the wrong result which can be very confusing. This means for each copy action I must check if the target folder exists and use a different command. That is very cumbersome but I am not aware of a more simple solution.
Unresolved situation for Case2
However, the problem I have is this one: When I use variables for the source and target my script looks like this
#!/bin/bash
SOURCE="source"
TARGET="target"
if [ -d "$TARGET" ]; then
cp -r $SOURCE $TARGET
else
cp -r $SOURCE/* $TARGET # note "$SOURCE/*" would fail.
fi
and I have a $SOURCE path with spaces.
SOURCE="source code"
Since I can not use quotations for the source variable, this causes two 'directory not found errors'.
How can I solve this for Case2?
EDIT
To clarify the problem a bit more. This
SOURCE="source"
cp -r "$SOURCE/*" $TARGET
fails with the error "cannot stat source/: No such file or directory". I think that means that bash can not replace the / with the file list and cp gets this as a file literal. A file or folder with the name "source/*" obviously does not exist. But maybe I am thinking too simple and what bash does is different.
Although your main issue concerns the cp
command there is also something I would like to say about your try. So lets get it step by step.
cp
behaviourThe cp
command behaves differently when the target folder contains a folder with the same name than the source folder. This behaviour is intended but can be avoided using the -T
option according to man.
Here you can find an extended explanation of the -T
option.
Thus, you can just execute:
cp -rT source/ target/
In your try you mention issues when handling paths using spaces. Although with the previous solution you don't need a custom script, I want to highlight that variables with paths containing spaces require all accesses to be double-quoted. The variable content must be double-quoted, not the star (since you want the globstar to expand, not to be taken literally). Hence, your previous script would look like this:
#!/bin/bash
SOURCE=${1:-"source"}
TARGET=${2:-"target"}
if [ -d "$TARGET" ]; then
cp -r "$SOURCE" "$TARGET"
else
cp -r "$SOURCE"/* "$TARGET" # note "$SOURCE/*" would fail.
fi