문제

어 절대적 또는 상대적인 경로(에서 유닉스 시스템),내가 결정의 전체 경로를 대상 후 해결하는 모든 중간 심볼릭 링크.보너스 포인트 또한 해결~username 표기에서 동일한 시간입니다.

상적으로 작동하지 않는다면,디렉토리할 수 있습 chdir()디렉토리고 그런 다음 전화 getcwd(),그러나 정말 하고 싶이에서 쉘 스크립트를 작성하는 것보다는 C helper.불행하게도,껍질을하는 경향이 있을 숨기려고 존재의 심볼릭 링크에서는 사용자(이 bash OS X):

$ ls -ld foo bar
drwxr-xr-x   2 greg  greg  68 Aug 11 22:36 bar
lrwxr-xr-x   1 greg  greg   3 Aug 11 22:36 foo -> bar
$ cd foo
$ pwd
/Users/greg/tmp/foo
$

내가 무엇을 원하는 기능을 해결하()같은 경우에서 실행 tmp 디렉토리 위의 예에서 확("foo")=="/사용자/그렉/tmp/bar".

도움이 되었습니까?

해결책

에 따라 표준 pwd -P 반환해야 경로 심볼릭 링크는 해결됩니다.

C 능 char *getcwd(char *buf, size_t size)unistd.h 이 동일해야 합니다.

getcwd pwd

다른 팁

readlink -f "$path"

편집자 노트:상기와 함께 작동 GNU readlinkFreeBSD/PC BSD/OpenBSD readlink, 하지만, OS X 에서의 10.11.
GNU readlink 제공하는 추가적인,관련 옵션과 같은 -m 에 대한 해결하는 링크는지 여부는 궁극적 목표이 존재합니다.

참고 이후 GNU 않 8.15(2012-01-06),가 realpath 프로그램을 사용할 수 있는 더 적은 둔 그보다 더 유연합니다.그것은 또한 호환 FreeBSD util 의 동일한 이름입니다.그것은 또한 기능이 포함되어 있을 생성하는 상대 사이의 경로는 두 개의 파일이 있습니다.

realpath $path

[관리자 또 아래에서 주석으로 halloleodanorton]

Mac OS X(적어도 10.11.x),사용 readlink 이 없 -f 옵션:

readlink $path

편집자 노트:이를 해결하지 않을 것이다 심볼릭 링크 재귀적으로 따라서 없 보고 궁극 target;예를 들어,주어지는 심볼릭 링크 a 는 점을 b, 에 포인트를 c, 이 것만 보고서 b (지 않도록 그것은 출력으로 절대 경로).
다음 perl 명령 OS X 에서의 간격을 메우는 없 readlink -f 기능:
perl -MCwd -le 'print Cwd::abs_path(shift)' "$path"

"pwd-P"작동하는 것 같다면 당신이 원하는 디렉토리,그러나 몇 가지 이유로 당신의 이름 실제 실행 파일을 생각하지 않는 도움이 됩니다.여기 나의 솔루션:

#!/bin/bash

# get the absolute path of the executable
SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0")

# resolve symlinks
while [[ -h $SELF_PATH ]]; do
    # 1) cd to directory of the symlink
    # 2) cd to the directory of where the symlink points
    # 3) get the pwd
    # 4) append the basename
    DIR=$(dirname -- "$SELF_PATH")
    SYM=$(readlink "$SELF_PATH")
    SELF_PATH=$(cd "$DIR" && cd "$(dirname -- "$SYM")" && pwd)/$(basename -- "$SYM")
done

나의 즐겨찾기 realpath foo

realpath - return the canonicalized absolute pathname

realpath  expands  all  symbolic  links  and resolves references to '/./', '/../' and extra '/' characters in the null terminated string named by path and
       stores the canonicalized absolute pathname in the buffer of size PATH_MAX named by resolved_path.  The resulting path will have no symbolic link, '/./' or
       '/../' components.
readlink -e [filepath]

을 것 같다 정확히 무엇을 요청 -받는 arbirary 경로를,해결하는 모든 심볼릭 링크 및 반환합니다""진짜 경로 -그리고 그것은"표준*nix"될 가능성이 있는 모든 이미 시스템

또 다른 방법:

# Gets the real path of a link, following all links
myreadlink() { [ ! -h "$1" ] && echo "$1" || (local link="$(expr "$(command ls -ld -- "$1")" : '.*-> \(.*\)$')"; cd $(dirname $1); myreadlink "$link" | sed "s|^\([^/].*\)\$|$(dirname $1)/\1|"); }

# Returns the absolute path to a command, maybe in $PATH (which) or not. If not found, returns the same
whereis() { echo $1 | sed "s|^\([^/].*/.*\)|$(pwd)/\1|;s|^\([^/]*\)$|$(which -- $1)|;s|^$|$1|"; } 

# Returns the realpath of a called command.
whereis_realpath() { local SCRIPT_PATH=$(whereis $1); myreadlink ${SCRIPT_PATH} | sed "s|^\([^/].*\)\$|$(dirname ${SCRIPT_PATH})/\1|"; } 

의 일부를 넣어 지정된 솔루션을 함께는 것을 알고,readlink 사용할 수 있는 대부분의 시스템에서,필요 하지만 다른 인수,이 작품에 대한 OSX 에서고 있습니다.나에 대한 확실하지 않 BSD 시스템입니다.어쩌면 상태야 [[ $OSTYPE != darwin* ]] 을 제외 -f 에서 OSX 니다.

#!/bin/bash
MY_DIR=$( cd $(dirname $(readlink `[[ $OSTYPE == linux* ]] && echo "-f"` $0)) ; pwd -P)
echo "$MY_DIR"

참고:저는 이것을 믿을 수 있는 고체,휴대용,준비가 만든 솔루션은 변함없이 는 이유입니다.

아래는 완전 POSIX 호환 스크립트/기능 그러므로 크로스-플랫폼 (에서 작동합 macOS 도,누구 readlink 도 지원 -f 로 10.12(Sierra))-그것은 사용 POSIX 쉘 언어 기능 만 POSIX 호환 유틸리티 호출합니다.

그것은 휴대용의 구현 GNU's readlink -e (보다 강력한 버전 readlink -f).

실행 스크립트sh기능bash, ksh, 고 zsh:

예를 들어,내부는 스크립트를 사용할 수 있습니다 그것은 다음과 같이 얻을 실행하는 스크립트의 진정한 디렉토리의 원산지와 함께,심볼릭 링크는 해결되:

trueScriptDir=$(dirname -- "$(rreadlink "$0")")

rreadlink 스크립트/기능의 정의:

코드 적응되었으로부터 감사 이 답변.
나 또한 만든 bash기반 stand-alone 유틸리티 버전 , 할 수 있는 설치
npm install rreadlink -g, 이 있는 경우 Node.js 설치됩니다.

#!/bin/sh

# SYNOPSIS
#   rreadlink <fileOrDirPath>
# DESCRIPTION
#   Resolves <fileOrDirPath> to its ultimate target, if it is a symlink, and
#   prints its canonical path. If it is not a symlink, its own canonical path
#   is printed.
#   A broken symlink causes an error that reports the non-existent target.
# LIMITATIONS
#   - Won't work with filenames with embedded newlines or filenames containing 
#     the string ' -> '.
# COMPATIBILITY
#   This is a fully POSIX-compliant implementation of what GNU readlink's
#    -e option does.
# EXAMPLE
#   In a shell script, use the following to get that script's true directory of origin:
#     trueScriptDir=$(dirname -- "$(rreadlink "$0")")
rreadlink() ( # Execute the function in a *subshell* to localize variables and the effect of `cd`.

  target=$1 fname= targetDir= CDPATH=

  # Try to make the execution environment as predictable as possible:
  # All commands below are invoked via `command`, so we must make sure that
  # `command` itself is not redefined as an alias or shell function.
  # (Note that command is too inconsistent across shells, so we don't use it.)
  # `command` is a *builtin* in bash, dash, ksh, zsh, and some platforms do not 
  # even have an external utility version of it (e.g, Ubuntu).
  # `command` bypasses aliases and shell functions and also finds builtins 
  # in bash, dash, and ksh. In zsh, option POSIX_BUILTINS must be turned on for
  # that to happen.
  { \unalias command; \unset -f command; } >/dev/null 2>&1
  [ -n "$ZSH_VERSION" ] && options[POSIX_BUILTINS]=on # make zsh find *builtins* with `command` too.

  while :; do # Resolve potential symlinks until the ultimate target is found.
      [ -L "$target" ] || [ -e "$target" ] || { command printf '%s\n' "ERROR: '$target' does not exist." >&2; return 1; }
      command cd "$(command dirname -- "$target")" # Change to target dir; necessary for correct resolution of target path.
      fname=$(command basename -- "$target") # Extract filename.
      [ "$fname" = '/' ] && fname='' # !! curiously, `basename /` returns '/'
      if [ -L "$fname" ]; then
        # Extract [next] target path, which may be defined
        # *relative* to the symlink's own directory.
        # Note: We parse `ls -l` output to find the symlink target
        #       which is the only POSIX-compliant, albeit somewhat fragile, way.
        target=$(command ls -l "$fname")
        target=${target#* -> }
        continue # Resolve [next] symlink target.
      fi
      break # Ultimate target reached.
  done
  targetDir=$(command pwd -P) # Get canonical dir. path
  # Output the ultimate target's canonical path.
  # Note that we manually resolve paths ending in /. and /.. to make sure we have a normalized path.
  if [ "$fname" = '.' ]; then
    command printf '%s\n' "${targetDir%/}"
  elif  [ "$fname" = '..' ]; then
    # Caveat: something like /var/.. will resolve to /private (assuming /var@ -> /private/var), i.e. the '..' is applied
    # AFTER canonicalization.
    command printf '%s\n' "$(command dirname -- "${targetDir}")"
  else
    command printf '%s\n' "${targetDir%/}/$fname"
  fi
)

rreadlink "$@"

측면에 보안:

jarno, 에서 참조하는 기능을 내장 command 지 않는 그림자에 의 별칭이나 쉘 기능 같은 이름의 요청서 코멘트:

어떤 경우 unaliasunset[ 는 별칭으로 설정하거나 쉘 기능은 무엇입니까?

의 뒤에 동기 부여 rreadlink 는 것을 보장 command 이 원래의 의미는 그것을 사용하는 바이패스(양) 편의 별칭과 기능을 자주 사용되는 그림자 표준에서 명령을 대화형 조개와 같은 재정의 ls 을 포함하는 옵션이 있습니다.

내가 안전하다고 생각하고 말하지 않는 한 당신과 함께 다루고 있어 신뢰할 수 없는,악의 환경에 대한 걱정 unaliasunset -또는 그 문제에 대 while, do,...-정이 문제가되지 않습니다.

는 기능에 의존해야합니다를 그것의 본래의 의미와 동작 주위에 방법이 없습니다.
는 POSIX 같은 쉘의 재정의 내부 명령하고 심지어는 키워드이 보안 위험(및 쓰고 편집증 코드입니에서 열심히 일반).

당신의 문제를 해결하기 위해 특별히:

기능에 의존 unaliasunset 그들의 원래 의미입니다.데이 그들로 재정의 쉘 기능 는 방식으로 바꾼 그들의 행동은 문제가 될;재정로 alias 가 반드시 우려 때문에, 인용 (부의)명령을 이름을(예를 들어, \unalias)시 별명이 있습니다.

그러나,인용가 옵션에 대한 포탄 키워드 (while, for, if, do,...)동안 쉘 키워드 마을보다 우선 shell 기능, 에 bashzsh 별칭이 우선 순위가 가장 높은,그래서 가드에 대한 포탄-키워드로 재정 실행해야 합니다 unalias 자신의 이름(이지만에 non-interactive bash 껍질(스크립트 등)별칭 기본적으로 확장을 아는 경우 shopt -s expand_aliases 은 명시적으로 호출의 첫 번째).

하는지 확인 unalias -으로 내장-는 그것의 원래 의미로 사용해야 합니다 \unset 그것은 먼저 요구하는 unset 이 원래의 의미는:

unset 은 셸 내장, 래는 것을 보장하기 위해 호출되는 이와 같이,당신이 있는지 확인해야 그 자체가 재정적으로 기능.하는 동안 당신을 우회할 수 있는 별칭 형태로 인용할 수 없습니다 우회 쉘 기능식-catch22.

따라서,할 수 없는 경우에 의존 unset 을 원래의 의미에서,내가 무엇을 말할 수 없을 보장하는 방법에 대한 방어 모든 악의적인 재정.

일반적인 쉘 스크립트는 종종 자신의 자리를 찾을 수"홈"디렉토리에 있는 경우에도로 호출되는 가리킵니다.스크립트라는 자신의 자리를 찾을 수"진짜"위치에서$0.

cat `mvn`

시스템에 인쇄를 포함하는 스크립트는 다음해야하는,좋은 힌트에서 당신이 필요합니다.

if [ -z "$M2_HOME" ] ; then
  ## resolve links - $0 may be a link to maven's home
  PRG="$0"

  # need this for relative symlinks
  while [ -h "$PRG" ] ; do
    ls=`ls -ld "$PRG"`
    link=`expr "$ls" : '.*-> \(.*\)$'`
    if expr "$link" : '/.*' > /dev/null; then
      PRG="$link"
    else
      PRG="`dirname "$PRG"`/$link"
    fi
  done

  saveddir=`pwd`

  M2_HOME=`dirname "$PRG"`/..

  # make it fully qualified
  M2_HOME=`cd "$M2_HOME" && pwd`
function realpath {
    local r=$1; local t=$(readlink $r)
    while [ $t ]; do
        r=$(cd $(dirname $r) && cd $(dirname $t) && pwd -P)/$(basename $t)
        t=$(readlink $r)
    done
    echo $r
}

#example usage
SCRIPT_PARENT_DIR=$(dirname $(realpath "$0"))/..

이것을 보십시오:

cd $(dirname $([ -L $0 ] && readlink -f $0 || echo $0))

므로 이 여러 번 수년에 걸쳐,그리고 이번에는 순수한 bash 휴대용 버전을 사용할 수 있는 on OSX 및 linux,내가 나서서 하나를 썼다:

살아있는 버전이 여기에 살고:

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

그러나의 이익을 위해서,여기에는 현재 버전(이것이 잘 테스트..그러나 나는 의견을 열고있어!)

되지 않을 수도 어려운 작업에 대한 일반 본 쉘(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
}

여기에는 전형적인 예이며,덕분에 brew:

%% 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-path:

%% 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 

의 주위에 일하는 맥 호환성,내놓았

echo `php -r "echo realpath('foo');"`

지 않지만 십자가 OS

여기에 어떻게 얻을 수 있는 하나 실제 파일의 경로를 MacOS/유닉스용 인라인 Perl 스크립트:

FILE=$(perl -e "use Cwd qw(abs_path); print abs_path('$0')")

마찬가지로,을 얻을 디렉토리의 symlinked file:

DIR=$(perl -e "use Cwd qw(abs_path); use File::Basename; print dirname(abs_path('$0'))")

는 당신의 경로를 디렉토리할 수 있다는 파일입니까?디렉토리라면,그것은 간단하다:

(cd "$DIR"; pwd -P)

그러나,경우에 있는 파일,다음이 작동 하지 않습니다.

DIR=$(cd $(dirname "$FILE"); pwd -P); echo "${DIR}/$(readlink "$FILE")"

기 때문에 심볼릭 링크를 해결할 수 있으로 상대 또는 전체 경로입니다.

스크립트에 나가 찾아야 실제 경로를 할 수 있도록 구성을 참조하거나 다른 설치되는 스크립트는 그것을 함께,내가 이것을 사용:

SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
  DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
  SOURCE="$(readlink "$SOURCE")"
  [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done

설정할 수 있습니다 SOURCE 어떤 파일 경로.기본적으로는 한,경로는 심볼릭 링크,그 해결합을 가리킵니다.트릭에서는 마지막 라인의합니다.을 경우 해결 symlink 은 절대적이,그것은 것으로 사용 SOURCE.그러나,그것은 상대의 경우,그것은 앞에 추가 DIR 한,그것이 해결되었으로 실제 위치에 의해 간단한 내가 먼저 설명한다.

저는 이것을 믿는 사실과 결정적인"방법을 해결하는 심볼릭 링크"지 디렉토리 또는 비를 사용하여 디렉토리 Bash:

function readlinks {(
  set -o errexit -o nounset
  declare n=0 limit=1024 link="$1"

  # If it's a directory, just skip all this.
  if cd "$link" 2>/dev/null
  then
    pwd -P "$link"
    return 0
  fi

  # Resolve until we are out of links (or recurse too deep).
  while [[ -L $link ]] && [[ $n -lt $limit ]]
  do
    cd "$(dirname -- "$link")"
    n=$((n + 1))
    link="$(readlink -- "${link##*/}")"
  done
  cd "$(dirname -- "$link")"

  if [[ $n -ge $limit ]]
  then
    echo "Recursion limit ($limit) exceeded." >&2
    return 2
  fi

  printf '%s/%s\n' "$(pwd -P)" "${link##*/}"
)}

모든 cdset 물건에.

여기에 내가 존재하는 것은 크로스-플랫폼(리눅스와 맥 os 어)솔루션을 답하는 작업에 대한 현재.

crosspath()
{
    local ref="$1"
    if [ -x "$(which realpath)" ]; then
        path="$(realpath "$ref")"
    else
        path="$(readlink -f "$ref" 2> /dev/null)"
        if [ $? -gt 0 ]; then
            if [ -x "$(which readlink)" ]; then
                if [ ! -z "$(readlink "$ref")" ]; then
                    ref="$(readlink "$ref")"
                fi
            else
                echo "realpath and readlink not available. The following may not be the final path." 1>&2
            fi
            if [ -d "$ref" ]; then
                path="$(cd "$ref"; pwd -P)"
            else
                path="$(cd $(dirname "$ref"); pwd -P)/$(basename "$ref")"
            fi
        fi
    fi
    echo "$path"
}

여기에 맥 os 만(?) 솔루션입니다.가능성에 더 적합한 원래 질문입니다.

mac_realpath()
{
    local ref="$1"
    if [[ ! -z "$(readlink "$ref")" ]]; then
        ref="$(readlink "$1")"
    fi
    if [[ -d "$ref" ]]; then
        echo "$(cd "$ref"; pwd -P)"
    else
        echo "$(cd $(dirname "$ref"); pwd -P)/$(basename "$ref")"
    fi
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top