web-dev-qa-db-ja.com

相対シンボリックリンクターゲットへの絶対パスを取得するためのテスト済みユーティリティを探しています

NB:この投稿の元のタイトルでは、「定評のある」という日常的な意味で、Wordstandardを使用しました。 (したがって、迅速な解決策とは対照的に、私は自分自身を転がすことができました)。ただし、Unixトークのコンテキストでは、Wordstandardには非常に具体的な(そして非常に異なる)技術的な意味があります。タイトルのWordstandardのこの代替の、より正確な解釈は、私の投稿の残りの部分に一貫性を持たせませんでした。 (これを指摘してくれたStéphaneChazelasに感謝します。)したがって、タイトルを改訂し、standardに置き換えました。テスト済み


タイトルで言及している問題の例として、以下に示すディレクトリ構造があるとします。

/tmp/example
├── a/
│   └── b/
│       └── c/
│           └── d/
│               └── target
└── A/
    └── B/
        ├── C/
        │   └── D/
        │       └── symlink-0 -> ../../symlink-1/b/c/d/target
        │
        └── symlink-1 -> /tmp/example/a

ご了承ください /tmp/example/A/B/C/D/symlink-0は、immediateターゲットがrelativeパスであるシンボリックリンクです。

$ readlink /tmp/example/A/B/C/D/symlink-0
../../symlink-1/b/c/d/target

このimmediateターゲットに対応する絶対パスを取得したいと思います。 IOW、partial解決を実行したい

/tmp/example/A/B/C/D/symlink-0 -> /tmp/example/A/B/symlink-1/b/c/d/target

これを行うための標準的な(または少なくとも十分に確立され、実績のある)Unixユーティリティはありますか?


ご了承ください readlink -fパスを完全に(シンボリックリンクのないパスに)解決します。ここで説明するケースの場合、たとえば、次のようになります。

$ readlink -f /tmp/example/A/B/C/D/symlink-0
/tmp/example/a/b/c/d/target

この意味は readlink -fnot私がここで尋ねている質問への答えです。


次のzsh関数のようなものに適切なエラーチェックなどを追加することで、自分でロールすることができます。

canonicalize () {
    local abspath=$(dirname $1)/$(readlink $1)
    printf -- '%s\n' $abspath:a
}

...しかし、この種のユーティリティを堅牢に実装することの難しさを過小評価しないように(難しい方法で)学んだので、可能であれば既存のツールを使用したいと思います。


FWIW、以下のスクリプトはこの投稿の例を生成します:

mkdir -p /tmp/example/a/b/c/d /tmp/example/A/B/C/D
touch /tmp/example/a/b/c/d/target
ln -s /tmp/example/a /tmp/example/A/B/symlink-1
ln -s ../../symlink-1/b/c/d/target /tmp/example/A/B/C/D/symlink-0
6
kjo

私はそのようなユーティリティを知りません。しかし、あなたのアプローチには欠陥があります(そして私はそれを正しくするのが非常に難しいことに同意します)。

_:a_修飾子は、ファイルシステムにアクセスせずに絶対パスを計算します。特に、_a/b/.._がシンボリックリンクであるかどうかに関係なく、_a/b_をaに変更します。

_/a/b -> ../foo_シンボリックリンクがある場合、それは_/foo_がシンボリックリンク自体でない場合にのみ_/a_です。 $(dirname $1)を正規化しても、x自体がシンボリックリンクである場合、_/a/b -> x/../../foo_のようなシンボリックリンクでは機能しません。

あなたの場合:

_/tmp/example/A/B/C/D/symlink-0 -> ../../symlink-1/b/c/d/target
_

_/tmp/example/A/B/symlink-1/b/c/d/target_も_/tmp/example/A/B/C/D_もシンボリックリンクではないため、_/tmp/example/A/B/C_に解決されます。

つまり、_.._コンポーネントを含まないシンボリックリンクのターゲットへの絶対パスを取得するには、複数のシンボリックリンクを解決する必要があり、ファイルのパスとシンボリックリンクのターゲット。

このようなパスが必要な場合、最も簡単な(そして合理的および/または有用な)アプローチは、シンボリックリンクのターゲットのcanonicalパスを取得することです。これは、すべてのパスコンポーネントが存在する場所です。 _.._、_._でも、シンボリックリンクでもありません。そのために、あなたはすることができます:

_zmodload -F zsh/stat b:zstat
canonicalize1() {
  if [ -L "$1" ]; then
    local link
    zstat -A link +link -- "$1" || return
    case $link in
      (/*) ;;
      (*)
        case $1:h in
          (*/) link=$1:h$link;;
          (*) link=$1:h/$link;;
        esac;;
    esac
    printf '%s\n' $link:h:A/$link:t
  else
    printf '%s\n' $1:A
  fi
}
_

_/tmp/example/A/B/C/D/symlink-0_シンボリックリンクでは、シンボリックリンクのターゲットがシンボリックリンクではないため、それでも_/tmp/example/a/b/c/d/target_が得られますが、それが目的でない場合は、次のように質問します。 :

_canonicalize1 /tmp/x/y
_

_/tmp/x/y_が_../foo_へのシンボリックリンクであり、_/tmp/x_が_/a/b/c_および_/a_へのシンボリックリンクである場合、_/a/b_、_/a/b/c_もそれ自体です。シンボリックリンク?

2