22

Is it possible to find out the full path to the script that is currently executing in KornShell (ksh)?

i.e. if my script is in /opt/scripts/myscript.ksh, can I programmatically inside that script discover /opt/scripts/myscript.ksh ?

Thanks,

javaPlease42
  • 4,699
  • 7
  • 36
  • 65
brabster
  • 42,504
  • 27
  • 146
  • 186

12 Answers12

27

You could use:

## __SCRIPTNAME - name of the script without the path
##
typeset -r __SCRIPTNAME="${0##*/}"

## __SCRIPTDIR - path of the script (as entered by the user!)
##
__SCRIPTDIR="${0%/*}"

## __REAL_SCRIPTDIR - path of the script (real path, maybe a link)
##
__REAL_SCRIPTDIR=$( cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P )
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Marnix
  • 294
  • 2
  • 3
  • 1
    Great answer - I was hoping this would also work if you source the script i.e. '. /some/script.sh' but it doesn't. – synthesizerpatel Nov 22 '13 at 02:33
  • 5
    @synthesizerpatel: In ksh93, you have `${.sh.file}` which also works for sourced files. – Mat M Jun 04 '14 at 14:19
  • 2
    As pointed out by Gruik, this doesn't work if there is a symbolic link to the shell script itself. So if you link the command into, say, /usr/bin, then __REAL_SCRIPTDIR will return /usr/bin, which is (most likely) not what you want. You do apparently need readlink for this – Tom Quarendon Jan 27 '15 at 14:42
10

In korn shell, all of these $0 solutions fail if you are sourcing in the script in question. The correct way to get what you want is to use $_

$ cat bar

echo dollar under is $_
echo dollar zero is $0

$ ./bar

dollar under is ./bar
dollar zero is ./bar

$ . ./bar
dollar under is bar
dollar zero is -ksh

Notice the last line there? Use $_. At least in Korn. YMMV in bash, csh, et al..

  • This answer should be incorporated into the accepted one. I was struggling for half an hour sourcing my ksh script until I realized that I need `$_`. – andreee Dec 22 '16 at 09:13
9

Well it took me a while but this one is so simple it screams.

_SCRIPTDIR=$(cd $(dirname $0);echo $PWD)

since the CD operates in the spawned shell with $() it doesn't affect the current script.

musefan
  • 47,875
  • 21
  • 135
  • 185
Mitch Brown
  • 91
  • 1
  • 1
8

How the script was called is stored in the variable $0. You can use readlink to get the absolute file name:

readlink -f "$0"
soulmerge
  • 73,842
  • 19
  • 118
  • 155
4

The variable $RPATH contains the relative path to the real file or the real path for a real file.

CURPATH=$( cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P )

CURLOC=$CURPATH/`basename $0`

if [ `ls -dl $CURLOC |grep -c "^l" 2>/dev/null` -ne 0 ];then

    ROFFSET=`ls -ld $CURLOC|cut -d ">" -f2 2>/dev/null`

    RPATH=`ls -ld $CURLOC/$ROFFSET 2>/dev/null`

else

    RPATH=$CURLOC

fi

echo $RPATH
arunkumar
  • 32,803
  • 4
  • 32
  • 47
  • This does appear to be the only method available that copes with the situation of a symlink to the script itself, horrible though it is. – Tom Quarendon Jan 27 '15 at 14:45
2

readlink -f would be the best if it was portable, because it resolves every links found for both directories and files.

On mac os x there is no readlink -f (except maybe via macports), so you can only use readlink to get the destination of a specific symbolic link file.

The $(cd -P ... pwd -P) technique is nice but only works to resolve links for directories leading to the script, it doesn't work if the script itself is a symlink

Also, one case that wasn't mentioned : when you launch a script by passing it as an argument to a shell (/bin/sh /path/to/myscript.sh), $0 is not usable in this case

I took a look to mysql "binaries", many of them are actually shell scripts ; and now i understand why they ask for a --basedir option or need to be launched from a specific working directory ; this is because there is no good solution to locate the targeted script

mklement0
  • 382,024
  • 64
  • 607
  • 775
Gruik
  • 31
  • 1
2

This is what I did:

if [[ $0 != "/"* ]]; then
  DIR=`pwd`/`dirname $0`
else
  DIR=`dirname $0`
fi
John Nilsson
  • 17,001
  • 8
  • 32
  • 42
1

Try which command.

which scriptname

will give you the full qualified name of the script along with its absolute path

Sachin
  • 20,805
  • 32
  • 86
  • 99
1

This works also, although it won't give the "true" path if it's a link. It's simpler, but less exact.

SCRIPT_PATH="$(whence ${0})"
mtruesdell
  • 3,697
  • 3
  • 21
  • 20
0

I upgraded the Edward Staudt's answer, to be able to deal with absolute-path symbolic links, and with chains of links too.

DZERO=$0
while true; do
  echo "Trying to find real dir for script $DZERO"
  CPATH=$( cd -P -- "$(dirname -- "$(command -v -- "$DZERO")")" && pwd -P )
  CFILE=$CPATH/`basename $DZERO`
  if [ `ls -dl $CFILE | grep -c "^l" 2>/dev/null` -eq 0 ];then
    break
  fi
  LNKTO=`ls -ld $CFILE | cut -d ">" -f2 | tr -d " " 2>/dev/null`
  DZERO=`cd $CPATH ; command -v $LNKTO`
done

Ugly, but works... After run this, the path is $CPATH and the file is $CFILE

Maciel
  • 1
-1

Try using this:

dir = $(dirname $0)
animuson
  • 53,861
  • 28
  • 137
  • 147
-1

Using $_ provides the last command.

>source my_script

Works if I issue the command twice:

>source my_script
>source my_script

If I use a different sequence of commands:

>who
>source my_script

The $_ variable returns "who"