web-dev-qa-db-ja.com

相対パスを絶対パスに変換しますか?

これらのパスが重複しているかどうかはわかりません。相対パスが与えられた場合、シェルスクリプトを使用して絶対パスを決定するにはどうすればよいですか?

例:

relative path: /x/y/../../a/b/z/../c/d

absolute path: /a/b/c/d
55
josh

このソース から:

#!/bin/bash

# Assume parameter passed in is a relative path to a directory.
# For brevity, we won't do argument type or length checking.

ABS_PATH=`cd "$1"; pwd` # double quotes for paths that contain spaces etc...
echo "Absolute path: $ABS_PATH"

Perlのワンライナーを実行することもできます。 Cwd::abs_path

48
DVK

UNIXで出会った中で最も信頼できる方法はreadlink -f

$ readlink -f /x/y/../../a/b/z/../c/d
/a/b/c/d

いくつかの注意事項:

  1. これには、すべてのシンボリックリンクを解決するという副作用もあります。これは望ましい場合と望ましくない場合がありますが、通常は望ましいことです。
  2. 存在しないディレクトリを参照すると、readlinkは空白の結果を返します。存在しないパスをサポートする場合は、readlink -m代わりに。残念ながら、このオプションは2005年以前にリリースされたreadlinkのバージョンには存在しません。
51
bukzor

bash を使用する

_# Directory
relative_dir="folder/subfolder/"
absolute_dir="$( cd "$relative_dir" && pwd )"

# File
relative_file="folder/subfolder/file"
absolute_file="$( cd "${relative_file%/*}" && pwd )"/"${relative_file##*/}"
_
  • _${relative_file%/*}_は、_dirname "$relative_file"_と同じ結果です
  • _${relative_file##*/}_は、_basename "$relative_file"_と同じ結果です

警告:シンボリックリンクを解決しません(つまり、パスを正規化しません)=>シンボリックリンクを使用する場合、すべての重複を区別できません。


realpathを使用

コマンド realpath はジョブを実行します。別の方法は、_readlink -e_(または_readlink -f_)を使用することです。ただし、realpathはデフォルトではインストールされません。 realpathまたはreadlinkが存在することを確認できない場合は、Perlを使用して置換できます(以下を参照)。


Perl を使用する

Steven Kramerrealpathがシステムで使用できない場合、シェルエイリアスを提案します。

_$ alias realpath="Perl -MCwd -e 'print Cwd::realpath(\$ARGV[0]),qq<\n>'"
$ realpath path/folder/file
/home/user/absolute/path/folder/file
_

または、直接Perlを使用する場合:

_$ Perl -MCwd -e 'print Cwd::realpath($ARGV[0]),qq<\n>' path/folder/file
/home/user/absolute/path/folder/file
_

この1行のPerlコマンドは_Cwd::realpath_を使用します。実際には、3つのPerl関数があります。単一の引数を取り、絶対パス名を返します。以下の詳細はドキュメントからです Perl5> Core modules> Cwd

  • abs_path()getcwd()と同じアルゴリズムを使用します。シンボリックリンクおよび相対パスコンポーネント(_._および_.._)は、 realpath と同様に、正規のパス名を返すように解決されます。

    _use Cwd 'abs_path';
    my $abs_path = abs_path($file);
    _
  • realpath()abs_path()の同義語です

    _use Cwd 'realpath';
    my $abs_path = realpath($file);
    _
  • fast_abs_path()はより危険ですが、abs_path()の潜在的に高速なバージョンです

    _use Cwd 'fast_abs_path';
    my $abs_path = fast_abs_path($file);
    _

これらの関数は、要求時にのみエクスポートされます=>したがって、Cwdを使用して、 arielf で指摘されている "Undefinedサブルーチン"エラーを回避します。これら3つの関数すべてをインポートする場合は、単一の_use Cwd_行を使用できます。

_use Cwd qw(abs_path realpath fast_abs_path);
_
19
olibre

「realpath」を見てください。

$ realpath

usage: realpath [-q] path [...]

$ realpath ../../../../../

/data/home
18
SteveMc

私は長年にわたってこれに何度も遭遇し、今回はOSXとLinuxで使用できる純粋なbashポータブルバージョンが必要だったので、先に書いて1つ書いた:

生きているバージョンはここにあります:

https://github.com/keen99/Shell-functions/tree/master/resolve_path

しかし、SOのために、現在のバージョンはここにあります(十分にテストされていると感じていますが、フィードバックを受け付けています!)

プレーンボーンシェル(sh)で動作させるのは難しくないかもしれませんが、私は試しませんでした...私は$ FUNCNAMEが大好きです。 :)

#!/bin/bash

resolve_path() {
    #I'm bash only, please!
    # usage:  resolve_path <a file or directory> 
    # follows symlinks and relative paths, returns a full real path
    #
    local owd="$PWD"
    #echo "$FUNCNAME for $1" >&2
    local opath="$1"
    local npath=""
    local obase=$(basename "$opath")
    local odir=$(dirname "$opath")
    if [[ -L "$opath" ]]
    then
    #it's a link.
    #file or directory, we want to cd into it's dir
        cd $odir
    #then extract where the link points.
        npath=$(readlink "$obase")
        #have to -L BEFORE we -f, because -f includes -L :(
        if [[ -L $npath ]]
         then
        #the link points to another symlink, so go follow that.
            resolve_path "$npath"
            #and finish out early, we're done.
            return $?
            #done
        Elif [[ -f $npath ]]
        #the link points to a file.
         then
            #get the dir for the new file
            nbase=$(basename $npath)
            npath=$(dirname $npath)
            cd "$npath"
            ndir=$(pwd -P)
            retval=0
            #done
        Elif [[ -d $npath ]]
         then
        #the link points to a directory.
            cd "$npath"
            ndir=$(pwd -P)
            retval=0
            #done
        else
            echo "$FUNCNAME: ERROR: unknown condition inside link!!" >&2
            echo "opath [[ $opath ]]" >&2
            echo "npath [[ $npath ]]" >&2
            return 1
        fi
    else
        if ! [[ -e "$opath" ]]
         then
            echo "$FUNCNAME: $opath: No such file or directory" >&2
            return 1
            #and break early
        Elif [[ -d "$opath" ]]
         then 
            cd "$opath"
            ndir=$(pwd -P)
            retval=0
            #done
        Elif [[ -f "$opath" ]]
         then
            cd $odir
            ndir=$(pwd -P)
            nbase=$(basename "$opath")
            retval=0
            #done
        else
            echo "$FUNCNAME: ERROR: unknown condition outside link!!" >&2
            echo "opath [[ $opath ]]" >&2
            return 1
        fi
    fi
    #now assemble our output
    echo -n "$ndir"
    if [[ "x${nbase:=}" != "x" ]]
     then
        echo "/$nbase"
    else 
        echo
    fi
    #now return to where we were
    cd "$owd"
    return $retval
}

醸造のおかげで、ここに古典的な例があります:

%% ls -l `which mvn`
lrwxr-xr-x  1 draistrick  502  29 Dec 17 10:50 /usr/local/bin/mvn@ -> ../Cellar/maven/3.2.3/bin/mvn

この関数を使用すると、-real-パスが返されます。

%% cat test.sh
#!/bin/bash
. resolve_path.inc
echo
echo "relative symlinked path:"
which mvn
echo
echo "and the real path:"
resolve_path `which mvn`


%% test.sh

relative symlinked path:
/usr/local/bin/mvn

and the real path:
/usr/local/Cellar/maven/3.2.3/libexec/bin/mvn
1
keen

これが役立つかもしれません:

$path = "~user/dir/../file" 
$resolvedPath = glob($path); #   (To resolve paths with '~')
# Since glob does not resolve relative path, we use abs_path 
$absPath      = abs_path($path);
0
Rohan