Bash: how to get real path of a symlink? [duplicate]
Asked Answered
A

3

43

Is it possible, executing a file symlinked in /usr/local/bin folder, to get the absolute path of original script? Well, .. I know where original file is, and I know it because I am linkging it. But, ... I want this script working, even if I move original source code (and symlink).

#!/bin/bash
echo "my path is ..."
Abrahamabrahams answered 22/4, 2015 at 6:14 Comment(6)
readlink is a function I can call in a bash script? I am trying but is not working =(Abrahamabrahams
readlink is a binary which is part of coreutilsRalph
readlink -f filename gives you a full path to link target.Origen
@PavelPatrin Only for GNU readlink, not for BSD.Demography
coreutils isn't installed by default on every system that includes bash. stat is more consistently available, but it too has different usage depending on your operating system.Modeling
Many tools exist for this. Just a few I have installed from Debian are realpath, chase and readlink. No doubt other platforms have a wide choice, too.Ruination
D
40

readlink is not a standard command, but it's common on Linux and BSD, including OS X, and it's the most straightforward answer to your question. BSD and GNU readlink implementations are different, so read the documentation for the one you have.

If readlink is not available, or you need to write a cross-platform script that isn't bound to a specific implementation:

If the symlink is also a directory, then

cd -P "$symlinkdir"

will get you into the dereferenced directory, so

echo "I am in $(cd -P "$symlinkdir" && pwd)"

will echo the fully dereferenced directory. That said, cd -P dereferences the entire path, so if you have more than one symlink in the same path you can have unexpected results.

If the symlink is to a file, not a directory, you may not need to dereference the link. Most commands follow symlinks harmlessly. If you simply want to check if a file is a link, use test -L.

Demography answered 22/4, 2015 at 6:27 Comment(4)
My "#!/bin/bash" script, doing the command: echo "I am in $(cd -P "$symlinkdir" && pwd)", print "/usr/local/bin/ttmux: line 4: cd: : No such file or directory"Abrahamabrahams
pwd has also the -P option. If you already are in the directory you can do : pwd -P. Also if you are not in : (cd /path/w/symlinks/ && pwd -P)Kief
after pwd -P , is there a way to do cd .. (without using copy and paste) ?Twist
What about cd -, @Twist ? Besides @Kief 's code is in parantheses and executes in a subshell, so it does not actually change current directory of the current shell.Drayton
C
39

lets assume we have real script or file and symbolic link to it:

$ ls -la
-rwxr-xr-x 1 root    root  0 Mar 20 07:05 realscript.sh
lrwxrwxrwx 1 root    root 10 Mar 20 07:05 symlink -> realscript.sh

And the part of GNU coreutils are few very useful commands:

$ realpath symlink
/home/test/realscript.sh

see also on original:

realpath realscript.sh
/home/test/realscript.sh

Also very good combination in scripting is to use dirname on script

$ dirname /home/test/realscript.sh
/home/test

so to wrap it up, you can use in script

echo  $( dirname $(realpath "symlink") )

or to get and store in variable real script home dir and save code to get real path script realscript.sh:

script_home=$( dirname $(realpath "$0") )
echo Original script home: $script_home

Where "$0" is defined as "self" in shell script.

To test everything, we put symlink into /home/test2/, amend some additional things and run/call it from root directory:

$ /home/test2/symlink
/home/test
Original script home: /home/test
Original script is: /home/test/realscript.sh
Called script is: /home/test2/symlink

Please try to write your self the amended outputs :)

Update 2021, there is also command:

readlink - print resolved symbolic links or canonical file names

DESCRIPTION Note realpath(1) is the preferred command to use for canonicalization functionality.

Comatose answered 20/3, 2019 at 6:30 Comment(0)
D
8

If you are working on GNU/Linux, you can use readlink: readlink -f $LINK On macOS you can also use the greadlink command: greadlink -f $LINK

Despicable answered 7/6, 2019 at 9:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.