在KornShell中,我能获取到当前脚本的绝对路径吗?

22

在KornShell(ksh)中,是否可能找出当前正在执行的脚本的完整路径?

也就是说,如果我的脚本位于/opt/scripts/myscript.ksh,是否可以在该脚本内编程方式发现/opt/scripts/myscript.ksh

谢谢。

12个回答

27

你可以使用以下代码:

## __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 )

1
非常好的答案 - 我希望这也适用于源脚本,即'. /some/script.sh',但它不起作用。 - synthesizerpatel
5
在ksh93中,${.sh.file}也适用于被引用的文件。 - Mat M
2
正如Gruik所指出的那样,如果有一个符号链接指向shell脚本本身,则此方法将无法工作。因此,如果您将命令链接到/usr/bin中,那么__REAL_SCRIPTDIR将返回/usr/bin,这可能不是您想要的结果。显然,您需要使用readlink来解决这个问题。 - Tom Quarendon

10
在Korn Shell中,如果您正在源代码中引用脚本,则所有这些$0解决方案都会失败。获取所需内容的正确方法是使用$ _。
$ 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

注意最后一行了吗?在Korn中使用 $_。在bash、csh等中可能会有所不同。


这个答案应该被合并到已接受的答案中。我花了半个小时在寻找我的ksh脚本,直到我意识到我需要使用 $_ - andreee

9

好吧,我花了一些时间,但这个问题非常简单,简直呼之欲出。

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

由于CD在使用$()生成的shell中运行,因此它不会影响当前脚本。


8

脚本的调用方式存储在变量$0中。您可以使用readlink来获取绝对文件名:

readlink -f "$0"

谢谢你的 $0 小费,readlink 是什么?我的系统上好像没有。 - brabster
嗯,需要完全在ksh内部实现,没有依赖项。谢谢。 - brabster
我恐怕这是不可能的 - 除非ksh有一种我不知道的与文件系统交互的可能性。你用的是什么操作系统? - soulmerge
3
$0 指的是命令被调用时的名称,它并不需要指向文件系统对象。 - Henk Langeveld

4
变量$RPATH包含真实文件的相对路径或真实文件的真实路径。
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

这似乎是唯一可用的方法,可以处理符号链接到脚本本身的情况,尽管它很糟糕。 - Tom Quarendon

2

这是我所做的:

if [[ $0 != "/"* ]]; then
  DIR=`pwd`/`dirname $0`
else
  DIR=`dirname $0`
fi

2

readlink -f 是最好的选择,因为它可以解析目录和文件中找到的所有链接。但是,它不够通用,不能在mac os x上使用(除非通过macports)。

在mac os x上,只能使用readlink来获取特定符号链接文件的目标。

$(cd -P ... pwd -P)技巧很好,但仅适用于解析指向脚本的目录的链接,如果脚本本身是符号链接,则无法使用。

还有一种情况未提及:当您将一个脚本作为参数传递给shell(/bin/sh /path/to/myscript.sh)时,此时$0无法使用。

我查看了mysql的“二进制”文件,其中许多实际上是shell脚本;现在我明白为什么它们要求使用--basedir选项或需要从特定的工作目录启动;这是因为没有好的方法来定位目标脚本。


1

尝试哪个命令。

which scriptname

将会给你脚本的完整限定名称以及其绝对路径


1

这个也可以工作,但如果它是一个链接,它不会给出“真实”的路径。它更简单,但不够精确。

SCRIPT_PATH="$(whence ${0})"

0

我升级了Edward Staudt的答案,以便能够处理绝对路径符号链接,以及链接链。

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

丑陋但有效... 运行后,路径为$CPATH,文件为$CFILE


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接