如何递归解析符号链接而无需readlink或realpath? [英] How to recursively resolve symlinks without readlink or realpath?

查看:156
本文介绍了如何递归解析符号链接而无需readlink或realpath?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果readlinkrealpath不可用,编写脚本以找到链接目标的最佳便携式(POSIX?)方法是什么?

What's the best portable (POSIX?) way to script finding the target for a link if readlink and realpath are not available?

您是否要ls -l,如果它以l开头,请在->之后以sed开头并重复,直到不再以l开头为止.

Would you ls -l, and if it starts with l take the text after the -> with sed and repeat until it no longer starts with l ?

推荐答案

BashFAQ#29 (它也支持@EugeniuRosca建议的建议的GNU查找方法):

Per BashFAQ #29 (which also endorses the GNU find approach suggested by @EugeniuRosca):

一个广泛可用的(虽然不是纯POSIX)选项是使用perl:

One widely available (though not pure-POSIX) option is to use perl:

target=/path/to/symlink-name perl -le 'print readlink $ENV{target}'

如果保证符号链接的名称不包含->,则可以解析ls的输出.

If your symlink's name is guaranteed not to contain ->, you can parse the output of ls.

以下代码结合了两种方法:

The below code combines both approaches:

# define the best readlink function available for this platform
if command -v readlink >/dev/null 2>/dev/null; then
  # first choice: Use the real readlink command
  readlink() {
    command readlink -- "$@"
  }
elif find . -maxdepth 0 -printf '%l' >/dev/null 2>/dev/null; then
  # second choice: use GNU find
  readlink() {
    local ll candidate >/dev/null 2>&1 ||:
    if candidate=$(find "$1" -maxdepth 0 -printf '%l') && [ "$candidate" ]; then
      printf '%s\n' "$candidate"
    else
      printf '%s\n' "$1"
    fi
  }
elif command -v perl >/dev/null 2>/dev/null; then
  # third choice: use perl
  readlink() {
    local candidate ||:
    candidate=$(target=$1 perl -le 'print readlink $ENV{target}')
    if [ "$candidate" ]; then
      printf '%s\n' "$candidate"
    else
      printf '%s\n' "$1"
    fi
  }
else
  # fourth choice: parse ls -ld
  readlink() {
    local ll candidate >/dev/null 2>&1 ||:
    ll=$(LC_ALL=C ls -ld -- "$1" 2>/dev/null)
    candidate=${ll#* -> }
    if [ "$candidate" = "$ll" ]; then
      printf '%s\n' "$1"
    else
      printf '%s\n' "$candidate"
    fi
  }
fi

readlink_recursive() {
    local path prev_path oldwd found_recursion >/dev/null 2>&1 ||:
    oldwd=$PWD; path=$1; found_recursion=0

    while [ -L "$path" ] && [ "$found_recursion" = 0 ]; do
        if [ "$path" != "${path%/*}" ]; then
          cd -- "${path%/*}" || {
            cd -- "$oldwd" ||:
            echo "ERROR: Directory '${path%/*}' does not exist in '$PWD'" >&2
            return 1
          }
          path=${PWD}/${path##*/}
        fi
        path=$(readlink "$path")
        if [ -d "$path" ]; then
          cd -- "$path"
          path=$PWD
          break
        fi
        if [ "$path" != "${path%/*}" ]; then
          cd -- "${path%/*}" || {
            echo "ERROR: Could not traverse from $PWD to ${path%/*}" >&2
            return 1
          }
          path=${PWD}/${path##*/}
        elif [ "$PWD" != "$oldwd" ]; then
          path=${PWD}/$path
        fi
        for prev_path; do
          if [ "$path" = "$prev_path" ]; then
            found_recursion=1
            break
          fi
        done
        set -- "$path" "$@" # record path for recursion check
    done

    if [ "$path" != "${path%/../*}" ]; then
      cd "${path%/*}" || {
        echo "ERROR: Directory '${path%/*}' does not exist in $PWD" >&2
        return 1
      }
      printf '%s\n' "$PWD/${path##*/}"
    else
      printf '%s\n' "$path"
    fi
    cd -- "$oldwd" ||:
}

这篇关于如何递归解析符号链接而无需readlink或realpath?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆