1

This code from Stack Overflow is to get the pathname to the parent directory of a script inside the script, even if the script is run via a symlink to it:

if [ -L $0 ] ; then
    DIR=$(dirname $(readlink -f $0)) ;
else
    DIR=$(dirname $0) ;
fi ;

Is the above code equivalent to

DIR=$(dirname $(readlink -f $0)) ;

i.e. is there really a need to test if $0 is a symlink, and run different commands if yes and if no?

Why not just use $(dirname $(readlink -f $0)) regardless of whether $0 contains symlink or not?

Specifically, if $0 contains symlink, then it is perfect to use $(dirname $(readlink -f $0)).

if $0 is not a symlink, then it seems perfect to me to just use $(dirname $(readlink -f $0)):

  • $(readlink -f $0) returns the absolute path of $0, and $(dirname $(readlink -f $0)) returns the absolute path to the parent directory of $0

  • $(dirname $0) returns a path to the parent of $0, whether the return is an absolute or relative path depending on if $0 is an absolute or relative path.

  • I don't think whether the value of DIR is an absolute or relative path is important in the original code, because in either case, the value of DIR refers to the parent directory of $0. So are $(dirname $(readlink -f $0)) and $(dirname $0) equivalent in the original code?

Thanks.

Toby Speight
  • 8,460
  • 3
  • 26
  • 50
Tim
  • 98,580
  • 191
  • 570
  • 977
  • `readlink -f` appears to allow you to specify a format on MacOS rather than 'force'. If the desired behavior is to get the real path of the given file, consider using `realpath` if available or `readlink "$0" || echo "$0"` for something more portable. – Beefster Oct 04 '21 at 16:31

2 Answers2

2

You should use "$0" and dirname "$()".

The commands are not equivalent because the shell test affects only the last component in the path but readlink -f affects all path levels.

mkdir physdir
touch physdir/file
ln -s physdir symlink
test -L symlink/file ; echo $?
    1
test -L symlink ; echo $?
    0
dirname symlink/file
    symlink
dirname "$(readlink -f symlink/file)"
    /crypto/home/hl/tmp/stackexchange/readlink/physdir

So for relative paths the output is quite different but even for absolute paths the symlink directories within differ.

Hauke Laging
  • 88,146
  • 18
  • 125
  • 174
  • Thanks. Still not sure about my question "If `$0` is not a symlink, then are `$(dirname $(readlink -f $0))` and `$(dirname $0) `equivalent?" see my edit – Tim Mar 21 '18 at 15:42
  • What do you mean by "the shell test affects only the last component in the path" and "readlink -f affects all path levels"? – Tim Mar 21 '18 at 16:06
  • @Tim See my edit. – Hauke Laging Mar 22 '18 at 10:58
  • Thanks. I see. I just clarified my question, see my edit. – Tim Mar 23 '18 at 20:10
  • My question is actually: Why not just use `$(dirname $(readlink -f $0))` regardless of whether `$0` contains symlink or not? – Tim Mar 24 '18 at 15:53
  • @Tim Is anyone saying you should not use it? If the output is what you want then just use it... – Hauke Laging Mar 24 '18 at 15:58
  • What is the purpose of the original code which treats `$0` differently depending on whether the last component of `$0` is a symlink, if its purpose is not the same as that of using `$(dirname $(readlink -f $0))` regardless of whether `$0` contains symlink or not? – Tim Mar 24 '18 at 16:01
  • @Tim I do not know the purpose of your code. – Hauke Laging Mar 24 '18 at 16:05
  • The purpose of the original code which test `-L $0` and treats `$0` differently based on the test is to get the pathname to the parent directory of a script inside the script, evne if the script is run via a symlink to it. I was wondering if the code can be simplified to using `$(dirname $(readlink -f $0))`regardless of whether `$0` contains symlink or not – Tim Mar 24 '18 at 16:12
2

I think whether there's a difference or not depends on the exact flavor of unix that you're using. On OSX for example, readlink doesn't have a -f flag and states:

If the given argument is not a symbolic link, readlink will print nothing and exit with an error

If you know that your OS supports the -f flag then there shouldn't be any difference.

In fact the -m flag might be the most flexible one to use.

MattM
  • 121
  • 1