BASH脚本获得自身路径方法
Shell中有一个命令叫pwd
(记忆:Print Working Directory的单词首字母)可以获得当前工作目录。如果该脚本在其所在目录下执行,使用pwd
命令可以得到脚本的当前目录。
# /home/user/scripts/getmydir.sh
MYDIR=`pwd`
echo $MYDIR
在/home/user/scripts目录下执行./getmydir.sh
得到脚本所在的绝对路径。
问题:但如果该脚本在其他目录下执行,比如在/home/user
下执行scripts/getmydir.sh
得到的路径却是/home/user/
。 原因在于pwd命令返回路径与脚本执行时的路径有关。
解决方法
可以看出pwd
命令获取脚本自身路径有一定限制,那么如何更加通用的获取执行脚本所在路径?
思路:我们需要先将工作目录切换到脚本所在目录,通过pwd
获取脚本目录,同时保证切换目录操作不影响shell当前目录。
BASH有两个内置变量可以帮忙:
FUNCNAME
bash内置变量,包含目前执行调用堆栈中所有shell函数名称的数组变量。FUNCNAME[0]
是当前正在执行的shell函数名,最高索引(栈底)的是函数main
(想象栈数据结构)
BASH_SOURCE
bash内置变量,是一个数组变量,其成员是FUNCNAME数组变量中定义的对应shell函数名。第一个元素是当前脚本的名称。这在source的时候非常有用,因为在被source的脚本中,$0是父脚本的名称,而不是被source的脚本名称。
BASH_SOURCE[0]
等价于 BASH_SOURCE, 取得当前执行的shell文件所在的路径及文件名。
方法一
我们可以用以下方法在任意目录执行该脚本获取其绝对路径:
# /home/user/scripts/getmydir2.sh
MYDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
将以上这条长命令分解来看就是:
DIR1="{BASH_SOURCE[0]}" #脚本相对于当前目录的路径,是相对路径
DIR2="$( dirname $DIR1 )" #得到脚本的目录名,也是相对路径
#cd命令切换到脚本所在目录,再执行pwd命令得到脚本绝对路径
MYDIR="$( cd $DIR2 && pwd )" #使用$()子shell执行命令不影响父进程
该脚本能成功的关键是BASH_SOURCE
环境变量。当用.
或source
执行脚本时,BASH_SOURCE
变量会自动设置到源文件路径。
方法二
还有一种方法就是前文介绍的readlink -f
命令显示canonical pathname达到效果。
DIR1="`dirname $BASH_SOURCE`"
MYDIR=`readlink -f "$DIR1"`
或者
DIR=$(dirname $(readlink -f "${BASH_SOURCE[0]}"))

