1

How to create a symlink to another symlink without following target symlink but keeping relative path between the target symlink and created symlink ?

Using the following structure for test

├── dst
│   
└── src
    ├── file.txt -> folder/file.txt
    └── folder
        └── file.txt


lrwxrwxrwx 1 user group 15 mars  16 20:05 src/file.txt -> folder/file.txt

Each time I try to create a symlink of src/file.txt (itself a relative symlink of src/folder/file.txt) in dst folder, the resulting symlink is never like dst/file.txt -> ../src/file.txt but always directly to the final target dst/file.txt -> ../src/folder/file.txt

ln -s -r [-T] 'src/file.txt' dst/file.txt

Only working without -r and specifying myself the relative path

ln -s '../src/file.txt' dst/file.txt

I need to use this inside a for loop for many files recursively and I would like to keep a relative path between the symlinks but without following target symlink, just a relative symlink to another symlink.

Is it possible to use ln with -r relative option without following target symlink ?

Regards

moocan
  • 111
  • 2
  • 11
  • When it's used, the value of the symlink is evaluated in the location of the filename .. so the value of file.txt has to be `../src/file.txt`. If you are in `dest` and do `ln -s ../src/file.txt file.txt` it will point to the link in the src folder and resolve to the `folder/file.txt` time when evaluated. This is a common idiom ... you have a symlink to a current version directory, then `./current/foo.bar` resolve to the one following the current link. You swap current and all the links automatically point to the new version. – Mr R Mar 16 '21 at 20:16
  • @MrR, hello, I'm testing from parent folder of `src/` and `dst/` folders like if I was doing a for loop like `for file in src/**/*; do ln s -r "${file}" "${file//src/dst}"; done` (better with `find ./src/ -type l` to catch only symlink in `src/`) which would create a new symlink in `dst/` for each symlink in `src/` keeping relative path between `src/dst`symlinks but without trying to follow the target symlink (keep only the symlink ref). Some tools have options to not follow symlink. I read man from `ln` but this is short. `ln -r` is practice to get relative path between target and link. – moocan Mar 16 '21 at 21:06
  • find seems much better - because it doesn't follow links but can find links ... e.g. from in the dst directory you could do something like this - `find ../src -type l -print0 | xargs -0 ln -s` OR if you wanted things with a particular pattern - `find ../src \( -type l -o -type f \) -name \*.txt -print0 | xargs -0 ln -s` – Mr R Mar 16 '21 at 21:10
  • @MrR I agree with you. I will use find. But my purpuse is to keep relative path between symlink from `src/` and `dst/` without following them. Relative `-r` option from `ln` is doing this out of the box but seems to follow symlink without preserving them. `dst/file.txt` symlink need to point to `/src/file.txt` symlink only (without following it's real value) and to be as `dst/file.txt -> ../src/file.txt`. Here it's simple because there is two folders but inside a hierarchy of over 1000 folders with many symlink it's different to get reltavive path between src/dst. – moocan Mar 16 '21 at 21:38
  • my example does what you describe. HOWEVER it's not as simple as this, if you have folders then presumably they can change too - so you need to create all of them before creating your links .. If you were doing the "in the directory create" you need to find all the directories having things you want to link to, create the directory in the `dst` and then link up the files. AND you'd want to make sure you don't end up with the `folder` files ... – Mr R Mar 16 '21 at 21:44
  • @MrR, So it's impossible to `ln` to not follow symlink using `-r` option. I need to use other tools to get realtive path between each symlink target and link before using an `ln` without `-r` otherwise link are not preserved and replaced with final target value. In `ln` man page `-r, --relative, create symbolic links relative to link location` `a relative link is interpreted in relation to its parent directory` but nowhere that symlink are not preserved and resolved. – moocan Mar 16 '21 at 21:57
  • @MrR, Sorry if I don't understood well what you mean :).`dst` folder will contains only symlink (no files) which will point to a symlink in the `src` folder. eg `dst/folder1/folder2/folderx/symlink` need to point to `src/folder1/folder2/folderx/symlink` (without resolving it's real value) by eg `src/folder1/folder2/folderx/symlink -> ../../../../src/folder1/folder2/folderx/symlink` It's only working with `ln -s` without `-r` so you need to get manualy the relative level of folders between them eg `../../../../` if you want to symlink a symlink without having as result the real file. – moocan Mar 16 '21 at 22:22
  • can you update your example folder structure with some more of the tree - e.g. some more folders in the src tree - then I'll give you 2 alternatives that I know work ... On OSX there's a `-h` option that is _-h If the target_file or target_dir is a symbolic link, do not follow it._ If your version of ln supports that maybe `-h -r` would work for you? – Mr R Mar 16 '21 at 22:30
  • @MrR, Argh, I don't have any `-h` options in my `ln` version (ubuntu 20.04 coreutils 8.30 http://manpages.ubuntu.com/manpages/focal/man1/ln.1.html). I will update with some more level tomorrow. But my difficuty is to link symlink to symlink preserving symlink (no follow) and get dynamically the relative level of folders between them. You can consider the same folder structure between `src` and `dst` with the same level depth. I'm trying with `realpath`. Thank you so much your help. – moocan Mar 16 '21 at 23:00
  • What about `-T` or `-n` options - they talk about not dereferencing? – Mr R Mar 17 '21 at 00:30
  • @MrR `-n Same as -h, for compatibility with other ln implementations.` `-n` or `-h` are related to `LINK_NAME` `treat LINK_NAME as a normal file if it is a symbolic link to a directory` not the `TARGET` in `ln [OPTION]... [-T] TARGET LINK_NAME`. Seems that a when `TARGET` is a symlink using `-r` is always followed. No option to prevent folowing symlink for the `TARGET` side. BSD man page have more info. – moocan Mar 17 '21 at 00:37
  • I think the -r option is what's causing you problems ... – Mr R Mar 17 '21 at 00:41
  • @MrR, only way I found is `ln -s "$(realpath -s --relative-to="$(dirname dst/file.txt)" src/file.txt)" dst/file.txt`. You are wright, with `ln -s` and `-r` impossible. Need to get the relative level/depth of folders between symlinks using other tools. – moocan Mar 17 '21 at 01:01

1 Answers1

1

Seems like ln -s -r follows links ..

Without the -r option ln -s puts in exactly what you type - so later the other link can be changed and the first directory still works.

# mkdir ABC
# mkdir DEF
# touch DEF/xx.txt
# ls -lAF DEF
total 8
drwxr-xr-x. 2 root root 4096 2021-03-17 11:40 ./
drwxrwxrwt. 4 root root 4096 2021-03-17 11:40 ../
-rw-r--r--. 1 root root    0 2021-03-17 11:40 xx.txt
# ln -s DEF/xx.txt 
# ls -laF
total 16
drwxrwxrwt.  4 root root 4096 2021-03-17 11:40 ./
drwxr-xr-x. 21 root root 4096 2017-03-17 14:13 ../
drwxr-xr-x.  2 root root 4096 2021-03-17 11:40 ABC/
drwxr-xr-x.  2 root root 4096 2021-03-17 11:40 DEF/
lrwxrwxrwx.  1 root root   10 2021-03-17 11:40 xx.txt -> DEF/xx.txt
# cd ABC/
# ln -s ../xx.txt 
# ls -laF
total 8
drwxr-xr-x. 2 root root 4096 2021-03-17 11:40 ./
drwxrwxrwt. 4 root root 4096 2021-03-17 11:40 ../
lrwxrwxrwx. 1 root root    9 2021-03-17 11:40 xx.txt -> ../xx.txt
# echo "ABC" > DEF/xx.txt
# cat ABC/xx.txt
ABC

So all the soft links are soft-links to another soft-link or the file - not resolved all the way through.

Mr R
  • 754
  • 7
  • 19