<p>Given an absolute or relative path (in a Unix-like system), I would like to determine the full path of the target after resolving any intermediate symlinks. Bonus points for also resolving ~username notation at the same time.</p>

<p>If the target is a directory, it might be possible to chdir() into the directory and then call getcwd(), but I really want to do this from a shell script rather than writing a C helper. Unfortunately, shells have a tendency to try to hide the existence of symlinks from the user (this is bash on OS X):</p>

<pre><code>$ ls -ld foo bar
drwxr-xr-x   2 greg  greg  68 Aug 11 22:36 bar
lrwxr-xr-x   1 greg  greg   3 Aug 11 22:36 foo -&gt; bar
$ cd foo
$ pwd
/Users/greg/tmp/foo
$
</code></pre>

<p>What I want is a function resolve() such that when executed from the tmp directory in the above example, resolve("foo") == "/Users/greg/tmp/bar".</p>

[{'answer_id': 7666, 'author': 'kauppi', 'author_id': 964, 'author_profile': 'https://Stackoverflow.com/users/964', 'pm_score': 8, 'selected': True, 'text': '<p>According to the standards, <code>pwd -P</code> should return the path with symlinks resolved.</p>\n\n<p>C function <code>char *getcwd(char *buf, size_t size)</code> from <code>unistd.h</code> should have the same behaviour.</p>\n\n<p><a href="http://www.opengroup.org/onlinepubs/009695399/functions/getcwd.html" rel="noreferrer">getcwd</a>\n<a href="http://www.opengroup.org/onlinepubs/009695399/utilities/pwd.html" rel="noreferrer">pwd</a></p>\n'}, {'answer_id': 7673, 'author': 'Hugo', 'author_id': 972, 'author_profile': 'https://Stackoverflow.com/users/972', 'pm_score': 2, 'selected': False, 'text': '<p>Common shell scripts often have to find their "home" directory even if they are invoked as a symlink. The script thus have to find their "real" position from just $0.</p>\n\n<pre><code>cat `mvn`\n</code></pre>\n\n<p>on my system prints a script containing the following, which should be a good hint at what you need.</p>\n\n<pre><code>if [ -z "$M2_HOME" ] ; then\n  ## resolve links - $0 may be a link to maven\'s home\n  PRG="$0"\n\n  # need this for relative symlinks\n  while [ -h "$PRG" ] ; do\n    ls=`ls -ld "$PRG"`\n    link=`expr "$ls" : \'.*-&gt; \\(.*\\)$\'`\n    if expr "$link" : \'/.*\' &gt; /dev/null; then\n      PRG="$link"\n    else\n      PRG="`dirname "$PRG"`/$link"\n    fi\n  done\n\n  saveddir=`pwd`\n\n  M2_HOME=`dirname "$PRG"`/..\n\n  # make it fully qualified\n  M2_HOME=`cd "$M2_HOME" &amp;&amp; pwd`\n</code></pre>\n'}, {'answer_id': 42918, 'author': 'pixelbeat', 'author_id': 4421, 'author_profile': 'https://Stackoverflow.com/users/4421', 'pm_score': 9, 'selected': False, 'text': '<pre><code>readlink -f "$path"\n</code></pre>\n\n<p><sup>Editor\'s note: The above works with <em>GNU</em> <code>readlink</code> and <em>FreeBSD/PC-BSD/OpenBSD</em> <code>readlink</code>, but <em>not</em> on OS X as of 10.11.<br>\n<em>GNU</em> <code>readlink</code> offers additional, related options, such as <code>-m</code> for resolving a symlink whether or not the ultimate target exists.</sup></p>\n\n<p>Note since GNU coreutils 8.15 (2012-01-06), there is a <strong>realpath</strong> program available that is less obtuse and more flexible than the above. It\'s also compatible with the FreeBSD util of the same name. It also includes functionality to generate a relative path between two files.</p>\n\n<pre><code>realpath $path\n</code></pre>\n\n<hr>\n\n<p>[Admin addition below from comment by <a href="/users/65889/halloleo">halloleo</a> —<a href="/users/65889/danorton">danorton]\n</a></p>\n\n<p>For Mac OS X (through at least 10.11.x), use <code>readlink</code> without the <code>-f</code> option:</p>\n\n<pre><code>readlink $path\n</code></pre>\n\n<p><sup>Editor\'s note: This will not resolve symlinks <em>recursively</em> and thus won\'t report the <em>ultimate</em> target; e.g., given symlink <code>a</code> that points to <code>b</code>, which in turn points to <code>c</code>, this will only report <code>b</code> (and won\'t ensure that it is output as an <em>absolute path</em>).<br>\nUse the following <code>perl</code> command on OS X to fill the gap of the missing <code>readlink -f</code> functionality:<br>\n<code>perl -MCwd -le \'print Cwd::abs_path(shift)\' "$path"</code></sup></p>\n'}, {'answer_id': 342461, 'author': 'Gregory', 'author_id': 14351, 'author_profile': 'https://Stackoverflow.com/users/14351', 'pm_score': 5, 'selected': False, 'text': "<p>One of my favorites is <code>realpath foo</code></p>\n\n<pre>\nrealpath - return the canonicalized absolute pathname\n\nrealpath  expands  all  symbolic  links  and resolves references to '/./', '/../' and extra '/' characters in the null terminated string named by path and\n       stores the canonicalized absolute pathname in the buffer of size PATH_MAX named by resolved_path.  The resulting path will have no symbolic link, '/./' or\n       '/../' components.\n</pre>\n"}, {'answer_id': 697552, 'author': 'tlrobinson', 'author_id': 113, 'author_profile': 'https://Stackoverflow.com/users/113', 'pm_score': 5, 'selected': False, 'text': '<p>"pwd -P" seems to work if you just want the directory, but if for some reason you want the name of the actual executable I don\'t think that helps. Here\'s my solution:</p>\n\n<pre><code>#!/bin/bash\n\n# get the absolute path of the executable\nSELF_PATH=$(cd -P -- "$(dirname -- "$0")" &amp;&amp; pwd -P) &amp;&amp; SELF_PATH=$SELF_PATH/$(basename -- "$0")\n\n# resolve symlinks\nwhile [[ -h $SELF_PATH ]]; do\n    # 1) cd to directory of the symlink\n    # 2) cd to the directory of where the symlink points\n    # 3) get the pwd\n    # 4) append the basename\n    DIR=$(dirname -- "$SELF_PATH")\n    SYM=$(readlink "$SELF_PATH")\n    SELF_PATH=$(cd "$DIR" &amp;&amp; cd "$(dirname -- "$SYM")" &amp;&amp; pwd)/$(basename -- "$SYM")\ndone\n</code></pre>\n'}, {'answer_id': 7400673, 'author': 'Keymon', 'author_id': 395686, 'author_profile': 'https://Stackoverflow.com/users/395686', 'pm_score': 3, 'selected': False, 'text': '<p>Another way:</p>\n\n<pre><code># Gets the real path of a link, following all links\nmyreadlink() { [ ! -h "$1" ] &amp;&amp; echo "$1" || (local link="$(expr "$(command ls -ld -- "$1")" : \'.*-&gt; \\(.*\\)$\')"; cd $(dirname $1); myreadlink "$link" | sed "s|^\\([^/].*\\)\\$|$(dirname $1)/\\1|"); }\n\n# Returns the absolute path to a command, maybe in $PATH (which) or not. If not found, returns the same\nwhereis() { echo $1 | sed "s|^\\([^/].*/.*\\)|$(pwd)/\\1|;s|^\\([^/]*\\)$|$(which -- $1)|;s|^$|$1|"; } \n\n# Returns the realpath of a called command.\nwhereis_realpath() { local SCRIPT_PATH=$(whereis $1); myreadlink ${SCRIPT_PATH} | sed "s|^\\([^/].*\\)\\$|$(dirname ${SCRIPT_PATH})/\\1|"; } \n</code></pre>\n'}, {'answer_id': 22991587, 'author': 'Dave', 'author_id': 689706, 'author_profile': 'https://Stackoverflow.com/users/689706', 'pm_score': 2, 'selected': False, 'text': '<pre><code>function realpath {\n    local r=$1; local t=$(readlink $r)\n    while [ $t ]; do\n        r=$(cd $(dirname $r) &amp;&amp; cd $(dirname $t) &amp;&amp; pwd -P)/$(basename $t)\n        t=$(readlink $r)\n    done\n    echo $r\n}\n\n#example usage\nSCRIPT_PARENT_DIR=$(dirname $(realpath "$0"))/..\n</code></pre>\n'}, {'answer_id': 25199441, 'author': 'Clemens Tolboom', 'author_id': 598513, 'author_profile': 'https://Stackoverflow.com/users/598513', 'pm_score': 1, 'selected': False, 'text': '<p>To work around the Mac incompatibility, I came up with</p>\n\n<pre><code>echo `php -r "echo realpath(\'foo\');"`\n</code></pre>\n\n<p>Not great but cross OS</p>\n'}, {'answer_id': 25560920, 'author': 'diyism', 'author_id': 264181, 'author_profile': 'https://Stackoverflow.com/users/264181', 'pm_score': 1, 'selected': False, 'text': '<p>Try this:</p>\n\n<pre><code>cd $(dirname $([ -L $0 ] &amp;&amp; readlink -f $0 || echo $0))\n</code></pre>\n'}, {'answer_id': 27642175, 'author': 'keen', 'author_id': 3692967, 'author_profile': 'https://Stackoverflow.com/users/3692967', 'pm_score': 1, 'selected': False, 'text': '<p>Since I\'ve run into this many times over the years, and this time around I needed a pure bash portable version that I could use on OSX and linux, I went ahead and wrote one:</p>\n\n<p>The living version lives here:</p>\n\n<p><a href="https://github.com/keen99/shell-functions/tree/master/resolve_path" rel="nofollow">https://github.com/keen99/shell-functions/tree/master/resolve_path</a></p>\n\n<p>but for the sake of SO, here\'s the current version (I feel it\'s well tested..but I\'m open to feedback!)</p>\n\n<p>Might not be difficult to make it work for plain bourne shell (sh), but I didn\'t try...I like $FUNCNAME too much. :)</p>\n\n<pre><code>#!/bin/bash\n\nresolve_path() {\n    #I\'m bash only, please!\n    # usage:  resolve_path &lt;a file or directory&gt; \n    # follows symlinks and relative paths, returns a full real path\n    #\n    local owd="$PWD"\n    #echo "$FUNCNAME for $1" &gt;&amp;2\n    local opath="$1"\n    local npath=""\n    local obase=$(basename "$opath")\n    local odir=$(dirname "$opath")\n    if [[ -L "$opath" ]]\n    then\n    #it\'s a link.\n    #file or directory, we want to cd into it\'s dir\n        cd $odir\n    #then extract where the link points.\n        npath=$(readlink "$obase")\n        #have to -L BEFORE we -f, because -f includes -L :(\n        if [[ -L $npath ]]\n         then\n        #the link points to another symlink, so go follow that.\n            resolve_path "$npath"\n            #and finish out early, we\'re done.\n            return $?\n            #done\n        elif [[ -f $npath ]]\n        #the link points to a file.\n         then\n            #get the dir for the new file\n            nbase=$(basename $npath)\n            npath=$(dirname $npath)\n            cd "$npath"\n            ndir=$(pwd -P)\n            retval=0\n            #done\n        elif [[ -d $npath ]]\n         then\n        #the link points to a directory.\n            cd "$npath"\n            ndir=$(pwd -P)\n            retval=0\n            #done\n        else\n            echo "$FUNCNAME: ERROR: unknown condition inside link!!" &gt;&amp;2\n            echo "opath [[ $opath ]]" &gt;&amp;2\n            echo "npath [[ $npath ]]" &gt;&amp;2\n            return 1\n        fi\n    else\n        if ! [[ -e "$opath" ]]\n         then\n            echo "$FUNCNAME: $opath: No such file or directory" &gt;&amp;2\n            return 1\n            #and break early\n        elif [[ -d "$opath" ]]\n         then \n            cd "$opath"\n            ndir=$(pwd -P)\n            retval=0\n            #done\n        elif [[ -f "$opath" ]]\n         then\n            cd $odir\n            ndir=$(pwd -P)\n            nbase=$(basename "$opath")\n            retval=0\n            #done\n        else\n            echo "$FUNCNAME: ERROR: unknown condition outside link!!" &gt;&amp;2\n            echo "opath [[ $opath ]]" &gt;&amp;2\n            return 1\n        fi\n    fi\n    #now assemble our output\n    echo -n "$ndir"\n    if [[ "x${nbase:=}" != "x" ]]\n     then\n        echo "/$nbase"\n    else \n        echo\n    fi\n    #now return to where we were\n    cd "$owd"\n    return $retval\n}\n</code></pre>\n\n<p>here\'s a classic example, thanks to brew:</p>\n\n<pre><code>%% ls -l `which mvn`\nlrwxr-xr-x  1 draistrick  502  29 Dec 17 10:50 /usr/local/bin/mvn@ -&gt; ../Cellar/maven/3.2.3/bin/mvn\n</code></pre>\n\n<p>use this function and it will return the -real- path:</p>\n\n<pre><code>%% cat test.sh\n#!/bin/bash\n. resolve_path.inc\necho\necho "relative symlinked path:"\nwhich mvn\necho\necho "and the real path:"\nresolve_path `which mvn`\n\n\n%% test.sh\n\nrelative symlinked path:\n/usr/local/bin/mvn\n\nand the real path:\n/usr/local/Cellar/maven/3.2.3/libexec/bin/mvn \n</code></pre>\n'}, {'answer_id': 31320634, 'author': 'Chuck Kollars', 'author_id': 742475, 'author_profile': 'https://Stackoverflow.com/users/742475', 'pm_score': 3, 'selected': False, 'text': '<pre><code>readlink -e [filepath]\n</code></pre>\n\n<p>seems to be exactly what you\'re asking for \n- it accepts an arbirary path, resolves all symlinks, and returns the "real" path\n- and it\'s "standard *nix" that likely all systems already have</p>\n'}, {'answer_id': 33266819, 'author': 'mklement0', 'author_id': 45375, 'author_profile': 'https://Stackoverflow.com/users/45375', 'pm_score': 2, 'selected': False, 'text': '<p><sup>Note: I believe this to be a solid, portable, ready-made solution, which is invariably <em>lengthy</em> for that very reason.</sup></p>\n\n<p>Below is a <strong>fully POSIX-compliant script / function</strong> that is therefore <strong>cross-platform</strong> (works on macOS too, whose <code>readlink</code> still doesn\'t support <code>-f</code> as of 10.12 (Sierra)) - it uses only <a href="http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#" rel="nofollow noreferrer">POSIX shell language features</a> and only POSIX-compliant utility calls.</p>\n\n<p>It is a <strong>portable implementation of GNU\'s <code>readlink -e</code></strong> (the stricter version of <code>readlink -f</code>).</p>\n\n<p>You can <strong>run the <em>script</em> with <code>sh</code></strong> or <strong>source the <em>function</em> in <code>bash</code>, <code>ksh</code>, and <code>zsh</code></strong>:</p>\n\n<p>For instance, inside a script you can use it as follows to get the running\'s script true directory of origin, with symlinks resolved:</p>\n\n<pre><code>trueScriptDir=$(dirname -- "$(rreadlink "$0")")\n</code></pre>\n\n<hr>\n\n<p><strong><code>rreadlink</code> script / function definition:</strong></p>\n\n<p><sup>The code was adapted with gratitude from <a href="https://stackoverflow.com/a/1116890/45375">this answer</a>.<br>\nI\'ve also created a <code>bash</code>-based stand-alone utility version <a href="https://github.com/mklement0/rreadlink" rel="nofollow noreferrer">here</a>, which you can install with<br>\n<code>npm install rreadlink -g</code>, if you have Node.js installed.</sup></p>\n\n<pre class="lang-sh prettyprint-override"><code>#!/bin/sh\n\n# SYNOPSIS\n#   rreadlink &lt;fileOrDirPath&gt;\n# DESCRIPTION\n#   Resolves &lt;fileOrDirPath&gt; to its ultimate target, if it is a symlink, and\n#   prints its canonical path. If it is not a symlink, its own canonical path\n#   is printed.\n#   A broken symlink causes an error that reports the non-existent target.\n# LIMITATIONS\n#   - Won\'t work with filenames with embedded newlines or filenames containing \n#     the string \' -&gt; \'.\n# COMPATIBILITY\n#   This is a fully POSIX-compliant implementation of what GNU readlink\'s\n#    -e option does.\n# EXAMPLE\n#   In a shell script, use the following to get that script\'s true directory of origin:\n#     trueScriptDir=$(dirname -- "$(rreadlink "$0")")\nrreadlink() ( # Execute the function in a *subshell* to localize variables and the effect of `cd`.\n\n  target=$1 fname= targetDir= CDPATH=\n\n  # Try to make the execution environment as predictable as possible:\n  # All commands below are invoked via `command`, so we must make sure that\n  # `command` itself is not redefined as an alias or shell function.\n  # (Note that command is too inconsistent across shells, so we don\'t use it.)\n  # `command` is a *builtin* in bash, dash, ksh, zsh, and some platforms do not \n  # even have an external utility version of it (e.g, Ubuntu).\n  # `command` bypasses aliases and shell functions and also finds builtins \n  # in bash, dash, and ksh. In zsh, option POSIX_BUILTINS must be turned on for\n  # that to happen.\n  { \\unalias command; \\unset -f command; } &gt;/dev/null 2&gt;&amp;1\n  [ -n "$ZSH_VERSION" ] &amp;&amp; options[POSIX_BUILTINS]=on # make zsh find *builtins* with `command` too.\n\n  while :; do # Resolve potential symlinks until the ultimate target is found.\n      [ -L "$target" ] || [ -e "$target" ] || { command printf \'%s\\n\' "ERROR: \'$target\' does not exist." &gt;&amp;2; return 1; }\n      command cd "$(command dirname -- "$target")" # Change to target dir; necessary for correct resolution of target path.\n      fname=$(command basename -- "$target") # Extract filename.\n      [ "$fname" = \'/\' ] &amp;&amp; fname=\'\' # !! curiously, `basename /` returns \'/\'\n      if [ -L "$fname" ]; then\n        # Extract [next] target path, which may be defined\n        # *relative* to the symlink\'s own directory.\n        # Note: We parse `ls -l` output to find the symlink target\n        #       which is the only POSIX-compliant, albeit somewhat fragile, way.\n        target=$(command ls -l "$fname")\n        target=${target#* -&gt; }\n        continue # Resolve [next] symlink target.\n      fi\n      break # Ultimate target reached.\n  done\n  targetDir=$(command pwd -P) # Get canonical dir. path\n  # Output the ultimate target\'s canonical path.\n  # Note that we manually resolve paths ending in /. and /.. to make sure we have a normalized path.\n  if [ "$fname" = \'.\' ]; then\n    command printf \'%s\\n\' "${targetDir%/}"\n  elif  [ "$fname" = \'..\' ]; then\n    # Caveat: something like /var/.. will resolve to /private (assuming /var@ -&gt; /private/var), i.e. the \'..\' is applied\n    # AFTER canonicalization.\n    command printf \'%s\\n\' "$(command dirname -- "${targetDir}")"\n  else\n    command printf \'%s\\n\' "${targetDir%/}/$fname"\n  fi\n)\n\nrreadlink "$@"\n</code></pre>\n\n<hr>\n\n<p><strong>A tangent on security:</strong></p>\n\n<p><a href="https://stackoverflow.com/users/4414935/jarno">jarno</a>, in reference to the function ensuring that builtin <code>command</code> is not shadowed by an alias or shell function of the same name, asks in a comment:</p>\n\n<blockquote>\n  <p>What if <code>unalias</code> or <code>unset</code> and <code>[</code> are set as aliases or shell functions?</p>\n</blockquote>\n\n<p>The motivation behind <code>rreadlink</code> ensuring that <code>command</code> has its original meaning is to use it to bypass (benign) <em>convenience</em> aliases and functions often used to shadow standard commands in interactive shells, such as redefining <code>ls</code> to include favorite options.</p>\n\n<p>I think it\'s safe to say that unless you\'re dealing with an untrusted, malicious environment, worrying about <code>unalias</code> or <code>unset</code> - or, for that matter, <code>while</code>, <code>do</code>, ... - being redefined is not a concern.</p>\n\n<p>There is <em>something</em> that the function must rely on to have its original meaning and behavior - there is no way around that.<br>\nThat POSIX-like shells allow redefinition of builtins and even language keywords is <em>inherently</em> a security risk (and writing paranoid code is hard in general).</p>\n\n<p>To address your concerns specifically:</p>\n\n<p>The function relies on <code>unalias</code> and <code>unset</code> having their original meaning. Having them redefined as <em>shell functions</em> in a manner that alters their behavior would be a problem; redefinition as an <em>alias</em> is\nnot necessarily a concern, because <em>quoting</em> (part of) the command name (e.g., <code>\\unalias</code>) bypasses aliases.</p>\n\n<p>However, quoting is <em>not</em> an option for shell <em>keywords</em> (<code>while</code>, <code>for</code>, <code>if</code>, <code>do</code>, ...) and while shell keywords do take precedence over shell <em>functions</em>, in <code>bash</code> and <code>zsh</code> aliases have the highest precedence, so to guard against shell-keyword redefinitions you must run <code>unalias</code> with their names (although in <em>non-interactive</em> <code>bash</code> shells (such as scripts) aliases are <em>not</em> expanded by default - only if <code>shopt -s expand_aliases</code> is explicitly called first).</p>\n\n<p>To ensure that <code>unalias</code> - as a builtin - has its original meaning, you must use <code>\\unset</code> on it first, which requires that <code>unset</code> have its original meaning:</p>\n\n<p><code>unset</code> is a shell <em>builtin</em>, so to ensure that it is invoked as such, you\'d have to make sure that it itself is not redefined as a <em>function</em>. While you can bypass an alias form with quoting, you cannot bypass a shell-function form - catch 22.</p>\n\n<p>Thus, unless you can rely on <code>unset</code> to have its original meaning, from what I can tell, there is no guaranteed way to defend against all malicious redefinitions.</p>\n'}, {'answer_id': 40584017, 'author': 'hpvw', 'author_id': 7155668, 'author_profile': 'https://Stackoverflow.com/users/7155668', 'pm_score': 3, 'selected': False, 'text': '<p>Putting some of the given solutions together, knowing that readlink is available on most systems, but needs different arguments, this works well for me on OSX and Debian. I\'m not sure about BSD systems. Maybe the condition needs to be <code>[[ $OSTYPE != darwin* ]]</code> to exclude <code>-f</code> from OSX only.</p>\n\n<pre><code>#!/bin/bash\nMY_DIR=$( cd $(dirname $(readlink `[[ $OSTYPE == linux* ]] &amp;&amp; echo "-f"` $0)) ; pwd -P)\necho "$MY_DIR"\n</code></pre>\n'}, {'answer_id': 45828988, 'author': 'solidsnack', 'author_id': 48251, 'author_profile': 'https://Stackoverflow.com/users/48251', 'pm_score': 2, 'selected': False, 'text': '<p>This is a symlink resolver in Bash that works whether the link is a directory or a non-directory:</p>\n\n<pre><code>function readlinks {(\n  set -o errexit -o nounset\n  declare n=0 limit=1024 link="$1"\n\n  # If it\'s a directory, just skip all this.\n  if cd "$link" 2&gt;/dev/null\n  then\n    pwd -P\n    return 0\n  fi\n\n  # Resolve until we are out of links (or recurse too deep).\n  while [[ -L $link ]] &amp;&amp; [[ $n -lt $limit ]]\n  do\n    cd "$(dirname -- "$link")"\n    n=$((n + 1))\n    link="$(readlink -- "${link##*/}")"\n  done\n  cd "$(dirname -- "$link")"\n\n  if [[ $n -ge $limit ]]\n  then\n    echo "Recursion limit ($limit) exceeded." &gt;&amp;2\n    return 2\n  fi\n\n  printf \'%s/%s\\n\' "$(pwd -P)" "${link##*/}"\n)}\n</code></pre>\n\n<p>Note that all the <code>cd</code> and <code>set</code> stuff takes place in a subshell.</p>\n'}, {'answer_id': 48513659, 'author': 'Igor Afanasyev', 'author_id': 1691455, 'author_profile': 'https://Stackoverflow.com/users/1691455', 'pm_score': 2, 'selected': False, 'text': '<p>Here\'s how one can get the actual path to the file in MacOS/Unix using an inline Perl script:</p>\n\n<pre><code>FILE=$(perl -e "use Cwd qw(abs_path); print abs_path(\'$0\')")\n</code></pre>\n\n<p>Similarly, to get the directory of a symlinked file:</p>\n\n<pre><code>DIR=$(perl -e "use Cwd qw(abs_path); use File::Basename; print dirname(abs_path(\'$0\'))")\n</code></pre>\n'}, {'answer_id': 51089005, 'author': 'Daniel C. Sobral', 'author_id': 53013, 'author_profile': 'https://Stackoverflow.com/users/53013', 'pm_score': 2, 'selected': False, 'text': '<p>Is your path a directory, or might it be a file? If it\'s a directory, it\'s simple:</p>\n\n<pre><code>(cd "$DIR"; pwd -P)\n</code></pre>\n\n<p>However, if it might be a file, then this won\'t work:</p>\n\n<pre><code>DIR=$(cd $(dirname "$FILE"); pwd -P); echo "${DIR}/$(readlink "$FILE")"\n</code></pre>\n\n<p>because the symlink might resolve into a relative or full path.</p>\n\n<p>On scripts I need to find the real path, so that I might reference configuration or other scripts installed together with it, I use this:</p>\n\n<pre><code>SOURCE="${BASH_SOURCE[0]}"\nwhile [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink\n  DIR="$( cd -P "$( dirname "$SOURCE" )" &amp;&amp; pwd )"\n  SOURCE="$(readlink "$SOURCE")"\n  [[ $SOURCE != /* ]] &amp;&amp; SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located\ndone\n</code></pre>\n\n<p>You could set <code>SOURCE</code> to any file path. Basically, for as long as the path is a symlink, it resolves that symlink. The trick is in the last line of the loop. If the resolved symlink is absolute, it will use that as <code>SOURCE</code>. However, if it is relative, it will prepend the <code>DIR</code> for it, which was resolved into a real location by the simple trick I first described.</p>\n'}, {'answer_id': 54179738, 'author': 'RuneImp', 'author_id': 3854664, 'author_profile': 'https://Stackoverflow.com/users/3854664', 'pm_score': 0, 'selected': False, 'text': '<p>Here I present what I believe to be a cross-platform (Linux and macOS at least) solution to the answer that is working well for me currently.</p>\n\n<pre><code>crosspath()\n{\n    local ref="$1"\n    if [ -x "$(which realpath)" ]; then\n        path="$(realpath "$ref")"\n    else\n        path="$(readlink -f "$ref" 2&gt; /dev/null)"\n        if [ $? -gt 0 ]; then\n            if [ -x "$(which readlink)" ]; then\n                if [ ! -z "$(readlink "$ref")" ]; then\n                    ref="$(readlink "$ref")"\n                fi\n            else\n                echo "realpath and readlink not available. The following may not be the final path." 1&gt;&amp;2\n            fi\n            if [ -d "$ref" ]; then\n                path="$(cd "$ref"; pwd -P)"\n            else\n                path="$(cd $(dirname "$ref"); pwd -P)/$(basename "$ref")"\n            fi\n        fi\n    fi\n    echo "$path"\n}\n</code></pre>\n\n<p>Here is a macOS (only?) solution. Possibly better suited to the original question.</p>\n\n<pre><code>mac_realpath()\n{\n    local ref="$1"\n    if [[ ! -z "$(readlink "$ref")" ]]; then\n        ref="$(readlink "$1")"\n    fi\n    if [[ -d "$ref" ]]; then\n        echo "$(cd "$ref"; pwd -P)"\n    else\n        echo "$(cd $(dirname "$ref"); pwd -P)/$(basename "$ref")"\n    fi\n}\n</code></pre>\n'}, {'answer_id': 57773331, 'author': 'Arunas Bartisius', 'author_id': 4494515, 'author_profile': 'https://Stackoverflow.com/users/4494515', 'pm_score': 0, 'selected': False, 'text': '<p>My answer here <a href="https://stackoverflow.com/questions/29789204/bash-how-to-get-real-path-of-a-symlink/55254754#55254754">Bash: how to get real path of a symlink?</a></p>\n\n<p>but in short very handy in scripts:</p>\n\n<pre><code>script_home=$( dirname $(realpath "$0") )\necho Original script home: $script_home\n</code></pre>\n\n<p>These are part of GNU coreutils, suitable for use in Linux systems.</p>\n\n<p>To test everything, we put symlink into /home/test2/, amend some additional things and run/call it from root directory:</p>\n\n<pre><code>/$ /home/test2/symlink\n/home/test\nOriginal script home: /home/test\n</code></pre>\n\n<p>Where </p>\n\n<pre><code>Original script is: /home/test/realscript.sh\nCalled script is: /home/test2/symlink\n</code></pre>\n'}, {'answer_id': 60309169, 'author': 'nakwa', 'author_id': 1643901, 'author_profile': 'https://Stackoverflow.com/users/1643901', 'pm_score': 2, 'selected': False, 'text': "<p>In case where pwd can't be used (e.g. calling a scripts from a different location), use realpath (with or without dirname):</p>\n\n<pre><code>$(dirname $(realpath $PATH_TO_BE_RESOLVED))\n</code></pre>\n\n<p>Works both when calling through (multiple) symlink(s) or when directly calling the script - from any location.</p>\n"}, {'answer_id': 73278862, 'author': 'dxlr8r', 'author_id': 19718625, 'author_profile': 'https://Stackoverflow.com/users/19718625', 'pm_score': 0, 'selected': False, 'text': "<p>My 2 cents. This function is POSIX compliant, and both the source and the destination can contain <code>-&gt;</code>. However, I have not gotten it work with filenames that container newline or tabs, as <code>ls</code> in general has issues with those.</p>\n<pre><code>resolve_symlink() {\n  test -L &quot;$1&quot; &amp;&amp; ls -l &quot;$1&quot; | awk -v SYMLINK=&quot;$1&quot; '{ SL=(SYMLINK)&quot; -&gt; &quot;; i=index($0, SL); s=substr($0, i+length(SL)); print s }'\n}\n</code></pre>\n<p>I believe the solution here is the <code>file</code> command, with a custom magic file that only outputs the destination of the provided symlink.</p>\n"}, {'answer_id': 73360081, 'author': 'Andi', 'author_id': 6307827, 'author_profile': 'https://Stackoverflow.com/users/6307827', 'pm_score': 0, 'selected': False, 'text': "<p>This is the best solution, tested in Bash 3.2.57:</p>\n<pre><code># Read a path (similar to `readlink`) recursively, until the physical path without any links (like `cd -P`) is found.\n# Accepts any existing path, prints its physical path and exits `0`, exits `1` if some contained links don't exist.\n# Motivation: `${BASH_SOURCE[0]}` often contains links; using it directly to extract your project's path may fail.\n#\n# Example: Safely `source` a file located relative to the current script\n#\n#     source &quot;$(dirname &quot;$(rreadlink &quot;${BASH_SOURCE[0]}&quot;)&quot;)/relative/script.sh&quot;\n#Inspiration: https://stackoverflow.com/a/51089005/6307827\nrreadlink () {\n    declare p=&quot;$1&quot; d l\n    while :; do\n        d=&quot;$(cd -P &quot;$(dirname &quot;$p&quot;)&quot; &amp;&amp; pwd)&quot; || return $? #absolute path without symlinks\n        p=&quot;$d/$(basename &quot;$p&quot;)&quot;\n        if [ -h &quot;$p&quot; ]; then\n            l=&quot;$(readlink &quot;$p&quot;)&quot; || break\n\n            #A link must be resolved from its fully resolved parent dir.\n            d=&quot;$(cd &quot;$d&quot; &amp;&amp; cd -P &quot;$(dirname &quot;$l&quot;)&quot; &amp;&amp; pwd)&quot; || return $?\n            p=&quot;$d/$(basename &quot;$l&quot;)&quot;\n        else\n            break\n        fi\n    done\n    printf '%s\\n' &quot;$p&quot;\n}\n</code></pre>\n"}]
['https://Stackoverflow.com/questions/7665', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/893/']