![如何获取链接目标的完整路径](https://linux22.com/image/1287987/%E5%A6%82%E4%BD%95%E8%8E%B7%E5%8F%96%E9%93%BE%E6%8E%A5%E7%9B%AE%E6%A0%87%E7%9A%84%E5%AE%8C%E6%95%B4%E8%B7%AF%E5%BE%84.png)
/var/opt/foo
如果我有一个用 创建的符号链接ln -fs /path/to/target/dir foo
。我怎样才能在只看到链接的脚本中获取/path/to/target/dir
?
我在脚本中想要实现的目标rm -rf /path/to/target/dir
在我做之前就已经实现了ln -fs /path/to/another/dir foo
。
答案1
link=/var/opt/foo
target=$(readlink "$link")
$target
现在是链接的目标,与它存储在文件系统中完全一样。
但是,符号链接可以是相对的,因此对于正常使用来说,这样会更好:
target=$(readlink -f "$link")
请注意,这使用了readlink
GNU Coreutils,它可能不存在于 BSD 和其他系统中。
编辑: readlink -f
只要链接目标存在,它就可以在 BSD 上运行。realpath
是另一个仅适用于 BSD 的工具,其工作方式类似。
答案2
此abspath()
功能适用于 Linux 和 BSD/OSX,包括您没有通过 homebrew 安装 GNU coreutils 的情况。
使用这种机制我会做这样的事情来解决你的例子:
f="$(abspath /path/to/target/dir)" && rm -rf "$f"
下面是我的跨平台 abspath 的实现:
function _abspath_the_hard_way ()
{ # See _abspath() for the rest of an implementation of something like GNU's `readlink -f`.
# assumes running under bash
# $1 : absolute or relative filename
# return : absolute path, sort of
local bn
bn="$(readlink "$1")"
if [ $? -ne 0 ] # if is not a symlink
then
bn="$(basename "$1")"
else
if [ -z "${bn%%/*}" ] # if linked-to starts with a /
then
echo "$bn"
return
fi
fi
if [ -d "$1" ]
then
(cd "$1" && pwd -P )
return
elif [[ $1 == /*/* ]]
then
echo "$(cd "${1%/*}" && pwd -P)/${bn}"
return
elif [[ $1 == /* ]]
then
echo "/$bn"
return
elif [[ $1 == ./* ]]
then
echo "$(pwd -P)/$bn"
return
elif [[ $1 == */* ]]
then
echo "$(cd "${1%/*}" && pwd -P)/$bn"
return
else
echo "$(pwd -P)/$bn"
return
fi
false
}
function _abspath ()
{
local x="$(sed -r 's,//+,/,g ; s,/[.]/,/,g' <<<"$1" )"
local y="$(_abspath_the_hard_way "$x" | sed -r 's,//+,/,g ; s,/[.]/,/,g' )"
while [ "$x" != "$y" ]
do
x="$(sed -r 's,//+,/,g ; s,/[.]/,/,g' <<<"$y" )"
y="$(_abspath_the_hard_way "$x")"
done
echo "$y"
}
_abspath_mechanism= # optimize to detect underlying mechanism only once
function abspath ()
{ # like `readlink -f` but should work on BSD, more or less
# $1 : relative filename
# return : absolute path
# See description of -f in GNU's readlink(1).
# Returns false if it can't resolve the path, true otherwise.
# It can return an empty string along with false.
case "$_abspath_mechanism" in
(readlink_f) readlink -f "$1" ; return ;;
(greadlink_f) greadlink -f "$1" ; return ;;
(_abspath) _abspath "$1" ; return ;;
esac
# Best is to simply call GNU's `readlink -f` if it's available.
if [ "$(uname -s)" = Linux ]
then
_abspath_mechanism=readlink_f
readlink -f "$1"
return
elif type greadlink >/dev/null 2>&1
then
# This is for if you're running OSX and have installed coreutils utilities via homebrew.
_abspath_mechanism=greadlink_f
greadlink -f "$1"
return
elif readlink -f / >/dev/null 2>&1
then
# Maybe you're running a non-Linux system that has a GNU readlink?
_abspath_mechanism=readlink_f
readlink -f "$1"
return
else
_abspath_mechanism=_abspath
_abspath "$1"
return
fi
}
答案3
一种方法是(我希望有一个更好的版本)
olddir=$(pwd)
cd /var/opt/foo
deleteme=$(pwd)
cd $olddir
rm -rf "$olddir"