Why does moving symlinked directory A to symlinked directory B cause A to be moved inside B?

StackOverflow https://stackoverflow.com/questions/18754104

سؤال

Scenario: I'm writing a shell script that checks to see if a directory exists; if it does, and it's a symlink, it renames the directory with .bak appended to the directory name. I noticed, however, that if I'm moving a symlinked directory (directory A) to another symlinked directory (B), it causes A to be moved inside B, rather than overwriting B.

To illustrate:

$ mkdir foo                                                                     
$ mkdir bar                                                                     
$ ln -s "$PWD/foo" ~/.baz                                                       
$ ls -al ~/.baz                                                                 
lrwxr-xr-x  1 ysim  staff  15 Sep 11 21:45 /Users/ysim/.baz -> /Users/ysim/foo  
$ mv ~/.baz ~/.bam                                                              
$ ls -al ~/.bam                                                                 
lrwxr-xr-x  1 ysim  staff  15 Sep 11 21:45 /Users/ysim/.bam -> /Users/ysim/foo  
$ ls -al ~/.baz                                                                 
ls: /Users/ysim/.baz: No such file or directory                                                                                                   
$ ln -s "$PWD/bar" ~/.baz                                                       
$ ls -al ~/.baz                                                                 
lrwxr-xr-x  1 ysim  staff  15 Sep 11 21:47 /Users/ysim/.baz -> /Users/ysim/bar  
$ ls -al ~/.bam                                                                 
lrwxr-xr-x  1 ysim  staff  15 Sep 11 21:45 /Users/ysim/.bam -> /Users/ysim/foo  

Now, when I rename/move ~/.baz to ~/.bam:

$ mv ~/.baz ~/.bam                 

The target of ~/.baz (/Users/ysim/bar) doesn't get moved to the target of ~/.bam, as expected:

$ ls -al ~/.bam                                                                 
lrwxr-xr-x  1 ysim  staff  15 Sep 11 21:45 /Users/ysim/.bam -> /Users/ysim/foo 

Instead, the entire ~/.baz symlink has been moved inside the ~/.bam directory:

$ ls -al ~/.bam/
total 8
drwxr-xr-x   3 ysim  staff   102 Sep 11 21:47 .
drwxr-xr-x+ 96 ysim  staff  3264 Sep 11 21:51 ..
lrwxr-xr-x   1 ysim  staff    15 Sep 11 21:47 .baz -> /Users/ysim/bar

Why is that? And how do I go about doing what I set out to do, which is to write the target of ~/.baz to the target of ~/.bam, so that ~/.bam has the destination /Users/ysim/bar?

هل كانت مفيدة؟

المحلول

It works like that because mv asks the OS to do the moving, and the OS dereferences symlinks. To behave differently mv would need extra code to check for symlinks and some --dereference-target, --dereference-src (or such) options. Think about the number of different behaviours different users might find desirable.

You need

rm "$dest"
cp -a "$src" "$dest"
# in your case src=".bam" and dest=".baz"

BTW if in a script you want to

  • "read" the target of a symlink in a script: target=$(readlink "$f")
  • test whether a file is a symlink: test -l "$f"
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top