cp into destination hierarchy with symbolic link?

4

1

I am trying to write a site deploy script that will copy files like so:

SOURCE

.
..
src/
html/

DEST

.
..
src/
html/ -> /var/www/ftproot/mysite

I want the files in SOURCE html to go to DEST /var/www/ftproot/mysite.

The script was:

cd SOURCE
cp -Rf * DEST

Every time I run the script, I get this error:

cp: cannot overwrite non-directory 'html' with directory `html'

From this, I deduce that cp cannot automatically copy files into DEST when DEST has symbolic links.

Notes:

  1. Following the cp manual, I set POSIXLY_CORRECT to 1. This doesn't work.

  2. I had to link site html to ftproot/mysite and not vice versa because the ftp users have weird access modes.

  3. This guy modified cp source code and recompiled it. I don't want to do that to a production server.

Any ideas on how to solve this?

est

Posted 2013-01-14T03:23:18.397

Reputation: 536

@Dennis Thank you, answers are: 1. yes (start with l when ls -l) 2. Ubuntu 10.04 server 3. Not safe to assume that – est – 2013-01-14T03:40:51.677

@Dennis yes you are correct. I edited my post. – est – 2013-01-14T03:52:38.747

Answers

5

for any file copying I would suggest rsync over cp because it has a much finer control what should be copied and how. In your case just give the commands:

cd SOURCE
rsync -K -a . DEST

The -K option does exactly what you want: -K, --keep-dirlinks treat symlinked dir on receiver as dir

sparkie

Posted 2013-01-14T03:23:18.397

Reputation: 2 110

Thank you for this. Exactly what I was looking for after cp -aPv --remove-destination started failing when we changed a directory to a symlink in the destination. – Artem Russakovskii – 2018-02-06T00:08:18.140

2

Since cp won't copy any directory in SOURCE over any symlink in DEST, one option is to copy those directories separately for each symlink.

Approach using find

cd DEST
cp -Rf SOURCE/* .
find -type l -exec bash -c 'cp -Rf "SOURCE/$0"/* "$0"' {} \;

Details

  • -type l restricts find to symlinks.
  • -exec bash -c '...' {} \; executes ... in a bash subshell for every found symlink, passing {} (the relative path to the symlink) as fitst argument ($0).
  • cp -Rf "SOURCE/$0"/* "$0" copies the contents of the corresponding source directory into the directory the symlink points to.
  • The cp command has to be invoked using bash, so the glob (asterisk) will get expanded.

Cautions

  • I suggest substituting cp with echo (or -Rf with -Ri) to make sure find does what you're expecting.
  • Without knowing the exact directory structure and the symlinks present in DEST, I can't guarantee that I anticipated all possible oddities.

Dennis

Posted 2013-01-14T03:23:18.397

Reputation: 42 934