I have a folder on my HDD /media/kalenpw/HDD/Documents/ShellScripts that is full of various scripts I would like to have accessible from any directory. My previous strategy was copying all of the files into /usr/local/bin this worked, but was tedious when updating scripts having to change in two places.

Luckily, I recently learned about symlinks and they are the perfect fit.

I made a test script in my home folder


print "Hello"

then I did ln ~/test.sh /usr/local/bin and like expected I could execute test.sh from anywhere.

The issue I'm having is I would prefer to keep all my documents on my HDD(at the directory given earlier). However, you can't link between drives so as expected I got an error

Invalid cross-device link

so I tried doing a symbolic link like so: sudo ln -s ./test.sh /usr/local/bin/ which created a link like expected. However, I can not execute test.sh from any directory(or even at all) like I would like. To ensure the file didn't lose permissions in the linking from /usr/local/bin I did sudo chmod +x ./test.sh and got an error:

chmod: cannot access './test.sh': Too many levels of symbolic links

I can't imagine there isn't a way to do this as it seems like a common usage, but I couldn't figure out how.

Summary: how can I create a link from one file to another on a different physical drive and still retain the ability to execute the linked file.

  • There is one fault in your symbolic link: When you say ln -s ./test.sh ... it does exactly that. If you do ls -l /usr/local/bin/test.sh, you will see the result: test.sh -> ./test.sh, so it points to itself - giving an endless loop when referencing. When crossing borders, you always should use full path: sudo ln -s /full-path-to-dir/test.sh /usr/local/bin will then work.
    – ridgy
    Feb 14 '17 at 9:25

1) The proper way to access lots of scripts is to just add the directory the scripts are in to your $PATH. For example, I have my personal scripts in ~/bin, so in my .profile, I have a line

export PATH=$HOME/bin:$PATH

That puts my ~/bin in front of the existings paths, so I'm able to "overwrite" other programs by having scripts with the same name. If you don't want that, put new directories after $PATH.

So just add the directory you keep your scripts in to your path, and your problem is solved - completely without symlinks.

2) Background: On a particular filesystem, files are indentified using their inode number. A directory just maps file names to inode numbers. If you use ln without -s (hardlinks), you are making a new directory entry with the inode of an existing file. So, obviously, this can only work for files on the same filesystem.

OTOH, if you use ln -s, you are making a symbolic link (symlink): A special file that has as contents the path you specify, and this path is used instead of the file when you try to access it. You don't need to be root to make symlinks.

3) When you do ln ~/test.sh /usr/local/bin, then the ln commands detects that /usr/local/bin is a directory, so it assumes your really want to execute ln ~/test.sh /usr/local/bin/test.sh. The same happens with -s. It's important to keep this in mind, because you can also make symlinks to directories. But only root can make hardlinks to directories, because you could create a circular directory structure this way (and root should know enough to not do that).

4) While a hardlink does have file mode bits, a symlink doesn't: Any attempt to chmod a symlink will just change the file mode bits on the file that it points to.

5) I don't know what happened when you couldn't execute test.sh, the Too many levels of symbolic links error message indicates you have other symbolic links somewhere, so something got messed up. I'd need to see your directory structure to find out what happened.

6) If you really want to symlink every single script in your script directory to /usr/local/bin/ instead of just setting the PATH (I don't recommend that), consider using stow instead: This program sets many symlinks at once. man stow for details.

  • 1
    Sorry for the late reply, I ended up adding it to $PATH and all works thanks for the answer
    – kalenpw
    Feb 15 '17 at 19:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.