シンボリックリンクなしの相対パスから絶対パスへの変換


回答:


79

オプションを指定readlinkしてユーティリティを使用でき-fます。

-f, --canonicalize

      canonicalize  by  following  every symlink in every component of
      the given name recursively; all  but  the  last  component  must
      exist

GNU coreutilsFreeBSDを使用するディストリビューションなど、一部のディストリビューションには、realpath(1)基本的に呼び出しrealpath(3)てほぼ同じことを実行するユーティリティも付属しています。


16
-fスイッチは、Mac OS X(10.8.5以上のような)に存在しません。-fスイッチがなければ、エラーコードを返すだけです。
iconoclast

3
一部のシステムには、特にSolarisとHP-UXのどちらreadlinkも付属していませんrealpath
シルドレス

Macの問題の場合:brew install coreutils apple.stackexchange.com/a/69332/23040、およびすべての標準Mac CLIツールを新しくインストールされたGNU同等物にリダイレクトするステップを実行したくない場合は、を呼び出しますgreadlink
エイドリアン

18

移植性があるため、PWD変数はシェルによって現在のディレクトリの1つの絶対位置に設定されます。そのパスのコンポーネントはシンボリックリンクである場合があります。

case $f in
  /*) absolute=$f;;
  *) absolute=$PWD/$f;;
esac

削除.したい場合は..、ファイルを含むディレクトリに移動して、$PWDそこから入手してください:

if [ -d "$f" ]; then f=$f/.; fi
absolute=$(cd "$(dirname -- "$f")"; printf %s. "$PWD")
absolute=${absolute%?}
absolute=$absolute/${f##*/}

シンボリックリンクをたどるポータブルな方法はありません。ディレクトリへのパスがある場合、$(cd -- "$dir" && pwd -P 2>/dev/null || pwd)シンボリックリンクを追跡するシェルは実装する傾向があるため、ほとんどの大学ではシンボリックリンクを使用しないパスを提供しますpwd -P(「物理」の「P」)。

一部の大学は、ファイルへの「物理」パスを出力するユーティリティを提供します。

  • かなり最近のLinuxシステム(GNU coreutilsまたはBusyBoxを使用)にはreadlink -f、FreeBSD≥8.3、NetBSD≥4.0、およびOpenBSD 2.2があります。
  • FreeBSD≥4.3にはrealpath(一部のLinuxシステムにも存在し、BusyBoxにあります)があります。
  • Perlが利用可能な場合、Cwdモジュールを使用できます

    perl -MCwd -e 'print Cwd::realpath($ARGV[0])' path/to/file

なぜpwd$(cd -- "$dir" && pwd -P 2>/dev/null | pwd))に何かをパイプするのですか?標準入力は気にしないようです。
マテウスピオトロフスキ

1
@MateuszPiotrowski Typo、私は書くつもりだった||
ジル「SO-悪であるのをやめ

5

であるpwdあなたのニーズに合いますか?現在のディレクトリの絶対パスを提供します。または多分あなたが望むのはrealpath()です。


3

alisterそして、rss67、この記事で最も安定した互換性と最も簡単な方法をご紹介します。これよりも良い方法を見たことはありません。

RELPATH=./../
cd $RELPATH
ABSPATH=`pwd`

元の場所に戻りたい場合は、

ORGPATH=`pwd`
RELPATH=./../
cd $RELPATH
ABSPATH=`pwd`
cd $ORGPATH

または

RELPATH=./../
cd $RELPATH
ABSPATH=`pwd`
cd -

これが役に立てば幸いです。これは私にとって最大の解決策でした。


12
それは実際にはそれほど良い方法ではありません。ディレクトリをいったん変更してから再び変更することは信頼できません。戻ってくる権限がないか、その間にディレクトリの名前が変更されている可能性があります。代わりに、サブシェルのディレクトリを変更しますABSPATH=$(cd -- "$RELPATH" && pwd)。置換を囲む二重引用符(パスに空白文字とグロビング文字が含まれている場合に壊れないように)と--(パスがで始まる場合)に注意してください-。また、これはディレクトリに対してのみ機能し、要求されたシンボリックリンクを正規化しません。詳細については私の答えをご覧ください。
ジル「SO-悪であるのをやめる」

">あなたは戻ってくる許可を持っていないかもしれない"あなたはdirにcdするが、cdできないことを意味する?いくつかのシナリオ例を提供してください。
Talespin_Kit

0

ここでの他の答えは結構でしたが、私のニーズには不十分でした。どのマシンのスクリプトでも使用できるソリューションが必要でした。私の解決策は、必要なスクリプトから呼び出すことができるシェルスクリプトを作成することでした。

#!/bin/sh
if [ $# -eq 0 ] || [ $# -gt 2 ]; then
  printf 'Usage: respath path [working-directory]\n' >&2
  exit 1
fi
cantGoUp=

path=$1
if [ $# -gt 1 ]; then
  cd "$2"
fi
cwd=`pwd -P` #Use -P option to account for directories that are actually symlinks

#Handle non-relative paths, which don't need resolution
if echo "$path" | grep '^/' > /dev/null ; then
  printf '%s\n' "$path"
  exit 0
fi

#Resolve for each occurrence of ".." at the beginning of the given path.
#For performance, don't worry about ".." in the middle of the path.
while true
do
  case "$path" in
    ..*)
      if [ "$cwd" = '/' ]; then
        printf 'Invalid relative path\n' >&2
        exit 1
      fi
      if [ "$path" = '..' ]; then
        path=
      else
        path=`echo "$path" | sed 's;^\.\./;;'`
      fi
      cwd=`dirname $cwd`
      ;;
    *)
      break
      ;;
  esac
done

cwd=`echo "$cwd" | sed 's;/$;;'`
if [ -z "$path" ]; then
  if [ -z "$cwd" ]; then
    cwd='/'
  fi
  printf '%s\n' "$cwd"
else
  printf '%s/%s\n' "$cwd" "$path"
fi

このソリューションは、移植性のためにBourne Shell用に作成されています。「respath.sh」という名前のスクリプトにこれがあります。

このスクリプトは次のように使用できます。

respath.sh '/path/to/file'

またはこのように

respath.sh '/relative/path/here' '/path/to/resolve/relative/to'

スクリプトは、2番目の引数からのパスを開始点として使用して、最初の引数のパスを解決します。最初の引数のみが指定されている場合、スクリプトは現在の作業ディレクトリからの相対パスを解決します。


最近のSolaris 10以前では、おそらくBourneシェルしか見つからないことに注意してください。それ SVR2(1984)がいるので、ボーンは、ほとんどのBourneシェルの実装のようなシェルpwd組み込みおよびサポートしていません-P(BourneシェルがPOSIXシェルが行うように取り扱い、その論理の$ PWDを実装していませんでした)。
ステファンシャゼル

Bourne互換性を落とす場合、POSIX $ {var ## pattern}構文を使用して、いくつかの値で壊れるecho | sedを避けることができます。
ステファンシャゼル

cd(およびpwd)の終了ステータスを確認するのを忘れています。cd -P --1番目の引数にいくつかの..が含まれている場合は、おそらく同様に使用する必要があります。
StéphaneChazelas

あなたのcaseチェックはする必要があります..|../*)代わりに..*
ステファンシャゼル

不足している引用符の1ケースがでありますdirname $cwd
ステファンChazelas

0

さらに、$1(通常${PWD})の事前定義されたパスがある場合、次のように機能します。

CWD="${1:-${PredefinedAbsolutePath}}"
if [ "${CWD}" != "${PredefinedAbsolutePath}}" ]; then
    case $1 in
        /*) echo "CWD=${CWD}"; ;;
        *) CWD=$(realpath $1); echo "CWD=${CWD}"; ;;
    esac
fi

0

他の皆の答えを尊重して、私は以下の機能がどこでも見つけた他のものよりもLinux / MAC OSX間で非常に簡単で移植性があることを発見しました。誰かを助けるかもしれない。

#!/usr/bin/bash
get_absolute_path(){
    file_path=`pwd $1`
    echo "$file_path/$1"
}
#to assign to a variable
absolute_path=$(get_absolute_path "file.txt")
echo $absolute_path

-1

変数aにパス名(a = "whatever")が格納されているとします

1.潜在的なスペースを含むパスの場合:

c=$(grep -o " " <<< $a | wc -l); if (( $c > "0" )); then a=$(sed 's/ /\\ /g' <<< $a); fi

2.実際の質問、つまりパスを絶対パスに変換する場合:readlinkはsymlinkコンテンツを取得できます。これは次のように使用できます。(注readlink -fは完璧でしたが、少なくともMac OS X bashでは使用できません。-fFORMATSを表します。)

if [[ $(readlink $a) == "" ]]; then a=$(cd $a; pwd); else a=$(cd $(readlink $a); pwd); fi

3.学習pwd -Pした内容man pwd:-Pは「物理的な現在の作業ディレクトリを表示する(すべてのシンボリックリンクが解決される)」ため、

if (( $(grep -o " " <<< $a | wc -l) > "0" )); then a=$(sed 's/ /\\ /g' <<< $a); fi; a=$(cd $a; pwd -P)

動作します。

結論:12を組み合わせて両方の要件を満たしますが、スペースを含むパス名はより簡潔な3ですでに処理されています。


あなたは間違っています。たとえば、パスにスペースが含まれている場合、上記のほとんどは機能しません。
アントン

または時々glob char。そして、要求されたように、シンボリックリンクを解決しません。
-dave_thompson_085

スペースを含むパス名に関する「コメント」応答を削除し、それに応じて「回答」部分を変更しました。
vxtal
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.