这是场景:
foo/
> data/
> stuff/
> scripts/ -> /.../generic/scripts
当从任何位置(其他文件夹或文件夹内)调用时foo/scripts/bar.sh
,我希望能够使用脚本foo/data
并foo/stuff
但是,如果我只是使用,foo_dir='dirname $0'/..
那么它将进入符号链接指向的目录! (并获取generic
而不是foo
!)
如果我使用某种模式来吃掉 的末尾$0
,那么它也不起作用,因为您也可以从目录内部调用脚本。
所以,最后,我唯一发现的就是这个极其丑陋的东西:
dir=`dirname $0`
cd $dir
dir=`pwd | sed -r 's_/[^/]+$__'`
cd -
...但我确信有更好的方法,不是吗?
我用的是:
dir=$( dirname $( cd `dirname $0`; pwd ) )
我不知道它是否完美,但它的表现似乎符合预期。
答案1
您可以使用以下单行:
DIR="$(cd "$( dirname "$0" )" && pwd )"
答案2
抱歉第一次没有更仔细地阅读你的问题。
代替:
foo_dir = $(dirname $0)/..
怎么样:
foo_dir = $(dirname $(dirname $0))
然而,这只适用于 $0 中至少有一个目录组件的情况。你有这个保证吗?
答案3
是的,..
符号链接的存在是一个真正的问题。罗布·派克写道关于这个问题的整篇论文。
我建议您避免..
使用dirname
绝对路径名,因此:
case $0 in
/*) where="$0" ;;
*) where="$(pwd)/$0" ;;
esac
# postcondition: $where is an absolute pathname for script
# N.B $where = .../foo/scripts/command
base="$(dirname "$(dirname "$where")")"
# postcondition: $base = .../foo
resource="$base/data"
我实际上使用第一个习惯用法(从可能的相对路径名恢复绝对路径名),我的~/bin
目录中有一个专门用于此目的的脚本。
一旦你处理绝对路径名,dirname
就会表现得明智。
答案4
你的帖子有点漫无目的,有些陈述似乎是矛盾的,但如果我的理解是正确的,你有一个$0
形式foo/scripts/bar.sh
,并且你正在尝试提取该foo
部分。您还可以保证该路径中始终至少有两级目录(如果您只有bar.sh
,那就完蛋了)。然后你可以去掉路径的最后两个组成部分:
DIR=${0%/*/*}
不过,您可以通过 调用脚本scripts/bar.sh
,在这种情况下,简单的模式替换将不起作用。更不用说通过$PATH
.您可以将其设置为有条件:
case $0 in
*/*/*) DIR=${0%/*/*};;
?*/*) DIR=.;;
/*) echo 1>&2 "Storing $0 in the root directory is not supported, aborting."
exit 125;;
*) # The script was called through the `PATH`
IFS=:; set -f; unset DIR
for d in $PATH; do
if [ -x "$d/$0" ]; then
# If you put relative directories in your PATH, you get what you deserve.
DIR=${d%/*};;
fi
done
if [ -z "$DIR" ]; then
echo 1>&2 "$0: Fatal error: I can't find myself."
exit 125
fi
unset IFS; set +f;;
esac