如何获取链接目标的完整路径

如何获取链接目标的完整路径

/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")

请注意,这使用了readlinkGNU 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"

相关内容