开发者

How can a ksh script determine the full path to itself, when sourced from another?

开发者 https://www.devze.com 2023-04-09 11:45 出处:网络
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

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: 开发者_如何学PythonI'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".


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


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).


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.


You should find it as last command in the history.

0

精彩评论

暂无评论...
验证码 换一张
取 消