6

How can a script determine it's path when it is sourced by ksh? i.e.

$ ksh ". foo.sh"

I've seen very nice ways of doing this in BASH posted on stackoverflow and elsewhere but haven't yet found a ksh method.

Using "$0" doesn't work. This simply refers to "ksh".

Update: I've tried using the "history" command but that isn't aware of the history outside the current script.

$ cat k.ksh
#!/bin/ksh
. j.ksh
$ cat j.ksh
#!/bin/ksh
a=$(history | tail -1)
echo $a
$ ./k.ksh
270 ./k.ksh

I would want it echo "* ./j.ksh".

Henk Langeveld
  • 8,088
  • 1
  • 43
  • 57
mathtick
  • 6,487
  • 13
  • 56
  • 101
  • **[This page](http://stackoverflow.com/questions/760110/can-i-get-the-absolute-path-to-the-current-script-in-korn-shell)** seems to have a working solution. – Anson Sep 30 '11 at 22:02
  • @Anson, I saw that but it doesn't work for me if I source the file, only if I run the script. – mathtick Oct 02 '11 at 20:40

4 Answers4

6

If it's the AT&T ksh93, this information is stored in the .sh namespace, in the variable .sh.file.

Example

sourced.sh:

(
 echo "Sourced: ${.sh.file}"
)

Invocation:

$ ksh -c '. ./sourced.sh'

Result:

Sourced: /var/tmp/sourced.sh

The .sh.file variable is distinct from $0. While $0 can be ksh or /usr/bin/ksh, or the name of the currently running script, .sh.file will always refer to the file for the current scope.

In an interactive shell, this variable won't even exist:

$ echo ${.sh.file:?}
-ksh: .sh.file: parameter not set
Community
  • 1
  • 1
Henk Langeveld
  • 8,088
  • 1
  • 43
  • 57
1

The difference of course between sourcing and forking is that sourcing results in the invoked script being executed within the calling process. Henk showed an elegant solution in ksh93, but if, like me, you're stuck with ksh88 then you need an alternative. I'd rather not change the default ksh method of sourcing by using C-shell syntax, and at work it would be against our coding standards, so creating and using a source() function would be unworkable for me. ps, $0 and $_ are unreliable, so here's an alternative:

$ cat b.sh ; cat c.sh ; ./b.sh

#!/bin/ksh
export SCRIPT=c.sh
. $SCRIPT 
echo "PPID: $$"
echo "FORKING c.sh"
./c.sh

If we set the invoked script in a variable, and source it using the variable, that variable will be available to the invoked script, since they are in the same process space.

#!/bin/ksh
arguments=$_
pid=$$
echo "PID:$pid"
command=`ps -o args -p $pid | tail -1`
echo "COMMAND (from ps -o args of the PID): $command"
echo "COMMAND (from c.sh's \$_ ) : $arguments"
echo "\$SCRIPT variable: $SCRIPT"
echo dirname: `dirname $0`
echo ; echo

Output is as follows:

PID:21665
COMMAND (from ps -o args of the PID): /bin/ksh ./b.sh
COMMAND (from c.sh's $_ ) : SCRIPT=c.sh
$SCRIPT variable: c.sh
dirname: .


PPID: 21665
FORKING c.sh
PID:21669
COMMAND (from ps -o args of the PID): /bin/ksh ./c.sh
COMMAND (from c.sh's $_ ) : ./c.sh
$SCRIPT variable: c.sh
dirname: .

So when we set the SCRIPT variable in the caller script, the variable is either accessible from the sourced script's operands, or, in the case of a forked process, the variable along with all other environment variables of the parent process are copied for the child process. In either case, the SCRIPT variable can contain your command and arguments, and will be accessible in the case of both sourcing and forking.

Dermot Canniffe
  • 167
  • 1
  • 8
1

I believe the only portable solution is to override the source command:

source() {
  sourced=$1
  . "$1"
}

And then use source instead of . (the script name will be in $sourced).

Dimitre Radoulov
  • 27,252
  • 4
  • 40
  • 48
0

You should find it as last command in the history.

ott--
  • 5,642
  • 4
  • 24
  • 27
  • Good idea but it's not working as expected (for me at least) ... I'll add my example code to the question since I can't post code easily here. – mathtick Oct 02 '11 at 20:42