188

I created this file structure:

test/src
test/firefox

When I run this command:

ln -s test/src test/firefox

I would expect a symbolic link test/firefox/src to be created pointing to test/src, however I get this error instead:

-bash: cd: src: Too many levels of symbolic links
  • What am I doing wrong?
  • Can you not create a symbolic link to one folder which is stored in a sibling of that folder?
  • What's the point of this?
polym
  • 10,672
  • 9
  • 41
  • 65
David Zorychta
  • 1,993
  • 2
  • 12
  • 6
  • I'm not sure I follow what you did. Please post the output of `ls -ld test test/*`, or the exact sequence of commands that you ran to create these files. – Gilles 'SO- stop being evil' Jul 09 '14 at 00:53
  • mkdir test; mkdir test/src; mkdir test/firefox; ln -s test/src test/firefox – David Zorychta Jul 09 '14 at 01:14
  • With these commands, `cd test/firefox/src` would show the error `cd: no such file or directory: test/firefox/src`, because `test/firefox/src` is a dangling symbolic link. Are you running `cd` on some other symbolic link called `src`? – Gilles 'SO- stop being evil' Jul 09 '14 at 01:18
  • I am sure you did something between the `ln -s` and the `cd` that you don't tell us. Assuming that there is only a `test` subdirectory in your current directory, a `cd src` (or whatever you executed) should throw an error. Did you put something into `test/firefox`? – Dubu Jul 09 '14 at 07:44
  • 9
    And as @Gilles gave a hint, that link will not do what you think it does. Symbolic links with relative targets are always relative to the _symlink directory_, not the directory from where you _created_ the link. So, being in a directory `/some/path`, a `ln -s test/src test/firefox` will create a symlink pointing from `/some/path/test/firefox/src` to `/some/path/test/firefox/test/src`, _not_ to `/some/path/test/src`. – Dubu Jul 09 '14 at 07:48
  • Are you sure you do not have a self-pointing link? – Konrad Gajewski Nov 24 '19 at 01:17

6 Answers6

303

As Dubu points out in a comment, the issue lies in your relative paths. I had a similar problem symlinking my nginx configuration from /usr/local/etc/nginx to /etc/nginx. If you create your symlink like this:

cd /usr/local/etc
ln -s nginx/ /etc/nginx

You will in fact make the link /etc/nginx -> /etc/nginx, because the source path is relative to the link's path. The solution is as simple as using absolute paths:

ln -s /usr/local/etc/nginx /etc/nginx

If you want to use relative paths and have them behave the way you probably expect them to, you can use the $PWD variable to easily add in the path to the current working directory path, like so:

cd /usr/local/etc
ln -s "$PWD/nginx/" /etc/nginx

Make sure that the path is in double quotes, to make sure things like spaces in your current path are escaped. Note that you must use double quotes when doing this, as $PWD will not be substituted if you use single quotes.

Steen Schütt
  • 3,562
  • 3
  • 15
  • 16
49

On the surface, what you've suggested you've tried works for me.

Example

$ mkdir -p test/src test/firefox

$ tree --noreport -fp
.
`-- [drwxrwxr-x]  ./test
    |-- [drwxrwxr-x]  ./test/firefox
    `-- [drwxrwxr-x]  ./test/src

Make the symbolic link:

$ ln -s test/src test/firefox

$ tree --noreport -fp
.
`-- [drwxrwxr-x]  ./test
    |-- [drwxrwxr-x]  ./test/firefox
    |   `-- [lrwxrwxrwx]  ./test/firefox/src -> test/src
    `-- [drwxrwxr-x]  ./test/src

Running it a 2nd time would typically produce this:

$ ln -s test/src test/firefox
ln: failed to create symbolic link ‘test/firefox/src’: File exists

So you likely have something else going on here. I would suspect that you have a circular reference where a link is pointing back onto itself.

You can use find to sleuth this out a bit:

$ cd /suspected/directory
$ find -L ./ -mindepth 15
polym
  • 10,672
  • 9
  • 41
  • 65
slm
  • 363,520
  • 117
  • 767
  • 871
  • 3
    `find -L ./ -mindepth 15` revealed the culprit – user7610 Oct 13 '16 at 12:49
  • It is certainly a symbolic link pointing to itself or this link point to another one that point to itself. I have seen this myself. Under Ubuntu, when you do ls -l, the link will blink; so it is hard to miss. – Kemin Zhou Dec 11 '19 at 23:58
22

Symlinks are relative to the parent directory of the link, not of the current directory of the ln process.

When you do:

cd /top/dir
ln -s test/src test/firefox

(where test/firefox is a directory), you're making a test/firefox/src symlink whose target is test/src.

That test/src is relative to the test/firefox directory, so that's a symlink to /top/dir/test/firefox/test/src.

If you wanted that symlink to be a link to /top/dir/test/src, you'd need to write:

ln -s ../src test/firefox/

Or

ln -s /top/dir/test/src test/firefox/

though it's generally a bad idea to make symlinks to absolute paths as they are easily broken when directories are renamed or filesystems are mounted elsewhere.

With GNU ln, you can use its -r option to let it make the calculation by itself:

$ ln -rs test/src test/firefox/
$ ls -ld test/firefox/src
lrwxrwxrwx 1 chazelas chazelas 6 Nov 29 15:59 test/firefox/src -> ../src
Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
14

Use the absolute path instead of the relative path, then it will work.

Eg:

ln -s /home/user/test/src /home/user/test/firefox
peterh
  • 9,488
  • 16
  • 59
  • 88
JISHNU T U
  • 141
  • 1
  • 3
  • Sometimes the issue is so simple. I was stuck for a while when I realized I used a relative path so the symlink was pointing to itself because it had the same name... upvoted – vdegenne Dec 19 '19 at 11:35
  • Just as a side note, you can indeed use relative paths and my advice is to generate a symlink directly from the directory where it will be created. For instance `cd ./foo` then `ln -s ../bar bar` (this symlink called `bar` will point the `bar` directory in the parent directory. – vdegenne Dec 19 '19 at 11:44
1

The answer is to use absolute path. But it can be annoying to type the full path for something that is in the current directory. You can use command substitution of pwd to avoid that. If your target is in the current directory:

ln -s "$(pwd)"/target abs/path/to/link 

If your link should be in the current directory:

ln -s /abs/path/to/target "$(pwd)"
breadnbeer
  • 11
  • 2
  • 1
    Note that POSIX shells have the `$PWD` special variable for that. That has the advantage over `$(pwd)` that it still works if the current directory ends in newline characters. Note that it's general better to use relative paths instead of absolute paths in the targets of symlinks as those with absolute paths are more easily broken when directories are renamed or moved or filesystems are mounted elsewhere. – Stéphane Chazelas Jul 02 '20 at 06:00
0

I've been battling with this for a while and absolute paths are not an option because I need to dockerize my pipeline where relative paths are critical. I finally figured it out:

SRC=$(realpath --relative-to "$DST" -- "$SRC")
Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
O.rka
  • 103
  • 3