source

셸 스크립트에서 심볼릭 링크를 확인하는 방법

manycodes 2023. 5. 6. 15:13
반응형

셸 스크립트에서 심볼릭 링크를 확인하는 방법

(Unix와 유사한 시스템에서) 절대 경로 또는 상대 경로가 주어지면 중간 심볼 링크를 해결한 후 대상의 전체 경로를 결정하고 싶습니다.~사용자 이름 표기법도 동시에 해결할 수 있는 보너스 포인트.

대상이 디렉토리라면 디렉토리에 chdir()를 입력한 다음 getcwd()를 호출할 수도 있지만, C 도우미를 작성하는 것보다 셸 스크립트에서 이 작업을 수행하고 싶습니다.안타깝게도 셸은 사용자에게 심볼릭 링크의 존재를 숨기려고 하는 경향이 있습니다(OS X의 경우 이는 bash입니다).

$ 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 디렉토리에서 실행될 때 resolve "foo") == "/Users/greg/tmp/bar"와 같은 함수 해결입니다.

readlink -f "$path"

편집자 참고 사항:위는 GNU와 연동됩니다. readlink FreeBSD/PC-BSD/OpenBSD readlink그러나 10.11 기준으로 OS X에는 없습니다.
readlink는) 같추인관가련옵제션공다합과 같은 을 제공합니다.-m최종 대상의 존재 여부에 관계없이 심볼릭 링크를 해결할 수 있습니다.

GNU 코어 8.15(2012-01-06)를 활용하기 때문에 위보다 덜 둔하고 더 유연한 실제 경로 프로그램이 있습니다.또한 FreeB와 호환됩니다.동일한 이름의 SD 사용률입니다.또한 두 파일 간의 상대 경로를 생성하는 기능도 포함되어 있습니다.

realpath $path

[할롤레오의 코멘트에서 아래 관리자 추가 - 댄튼]

X 10의 경우 Mac OS X 경최(문서 10.11)을 합니다.x를 통해),readlink 없이-f옵션:

readlink $path

편집자 참고 사항:이렇게 하면 심볼릭 링크가 재귀적으로 해결되지 않으므로 최종 대상을 보고하지 않습니다(예: 심볼릭 링크).a그것이 가리키는 바는b그것이 차례로 가리키는 것입니다.c 이은보할것니다입만만 보고됩니다.b(절대 경로로 출력되는지 확인하지 않습니다.)
의 다음사니를 합니다.perl에서 명령을 된 OS X의 공백을 .readlink -f기능:
perl -MCwd -le 'print Cwd::abs_path(shift)' "$path"

, 기에따르면준,면,,pwd -P심볼 링크가 확인된 경로를 반환해야 합니다.

함수 함char *getcwd(char *buf, size_t size)unistd.h같은 행동을 취해야 합니다.

getcwd pwd

"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 - 정규화된 절대 경로 이름을 반환합니다.
realpath는 모든 심볼 링크를 확장하고 경로 및 경로에 의해 이름이 지정된 null 끝 문자열에 있는 '//', '/../' 및 추가 '/' 문자에 대한 참조를 확인합니다.표준화된 절대 경로 이름을 resolved_path로 명명된 크기 PATH_MAX의 버퍼에 저장합니다.결과 경로에 기호 링크, '//' 또는'/..구성 요소
readlink -e [filepath]

정확히 당신이 요구하는 것처럼 보입니다. - 그것은 임의의 경로를 받아들이고, 모든 심볼릭 링크를 해결하고, "실제" 경로를 반환합니다. 그리고 그것은 모든 시스템이 이미 가지고 있을 가능성이 높은 "표준 *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|"; } 

대부분의 시스템에서 읽기 링크를 사용할 수 있지만 다른 인수가 필요하다는 것을 알고 주어진 솔루션 중 일부를 결합하면 OSX와 Debian에서 잘 작동합니다.BSD 시스템에 대해서는 잘 모르겠습니다.아마도 그 조건은[[ $OSTYPE != darwin* ]] 제외하다-fOSX에서만 사용할 수 있습니다.

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

인라인 Perl 스크립트를 사용하여 MacOS/Unix에서 파일의 실제 경로를 가져오는 방법은 다음과 같습니다.

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

마찬가지로, 심볼릭 링크된 파일의 디렉터리를 가져오려면:

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

일반 셸 스크립트는 심볼릭 링크로 호출되더라도 "홈" 디렉토리를 찾아야 하는 경우가 많습니다.따라서 스크립트는 $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`

경로가 디렉토리입니까, 아니면 파일입니까?디렉터리인 경우 다음과 같이 간단합니다.

(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파일 경로로 이동합니다.기본적으로 경로가 심볼릭 링크인 한 심볼릭 링크는 해결됩니다.속임수는 루프의 마지막 줄에 있습니다.확인된 심볼릭 링크가 절대적인 경우, 이 심볼릭 링크는 다음과 같이 사용됩니다.SOURCE그러나 상대적인 경우 다음과 같이 추가됩니다.DIR처음에 설명한 간단한 속임수로 실제 위치로 해결되었습니다.

pwd를 사용할 수 없는 경우(예: 다른 위치에서 스크립트를 호출하는 경우), realpath(dirname 사용 여부와 상관없이):

$(dirname $(realpath $PATH_TO_BE_RESOLVED))

(여러) 심볼 링크를 통해 호출할 때 또는 임의의 위치에서 스크립트를 직접 호출할 때 모두 작동합니다.

업데이트:

  • 적어도 macOS 13(Ventura) 이후, macOS궁극적인 목표(FreeB)에 대한 심볼릭 링크를 따르는 것도 지원합니다.SD는 훨씬 더 오랫동안 지원을 받아왔기 때문에 POSIX 호환 솔루션에 대한 필요성이 상당히 감소했습니다.

  • 그러나 아래 구현된 POSIX 호환 솔루션은 여전히 관심을 가질 수 있습니다.

    • 버전의 및 macOS에서 사용할 수 있습니다.readlink -f구현되지 않았습니다.

    • 플랫폼 전반에 걸쳐 일관된 동작이 필요합니다.

      • 특히.readlink -fmacOS / FreeB에서SD는 GNU 구현과 동등하지 않습니다(Linux distros에서 볼 수 있음). -f/ / FreeB 에서는 GNU SD(GNU)에합니다.-e인 대상의 인목표의강(GNU의 ))의를 의미합니다.-f최종 대상의 마지막 경로 세그먼트(segment)가 존재하지 않도록 합니다.

아래는 POSIX와 완전히 호환되는 스크립트/함수크로스 플랫폼(macOS에서도 작동)입니다.readlink 지원하지 -f10.12 (Sierra) 기준 - POSIX언어 기능과 POSIX 호환 유틸리티 호출만 사용합니다.

이것은 GNU의 휴대용 구현체입니다(의 더 엄격한 버전).readlink -f).

, 및 에서 함수를 사용하여 스크립트실행하거나 소스를 제공할 수 있습니다.

예를 들어 스크립트 내부에서 다음과 같이 사용하여 실행 중인 스크립트의 참 원본 디렉터리를 가져올 수 있으며 심볼 링크가 확인됩니다.

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

rreadlink스크립트/함수 정의:

코드는 이 답변에서 감사함을 담아 수정되었습니다.
또한 다음을 만들었습니다.bash여기에 설치할 수 있는 독립 실행형 유틸리티 버전
npm install rreadlink -gNode.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동일한 이름의 별칭 또는 셸 함수에 의해 음영 처리되지 않습니다. 코멘트에서 다음과 같이 묻습니다.

면 어쩌지unalias또는unset그리고.[별칭 또는 셸 함수로 설정됩니까?

뒤에 숨은 동기rreadlink을 확실히 하기 위해command원래의 의미는 이를 사용하여 편의 별칭을 우회(배제)하는 것이며, 상호 작용 셸에서 표준 명령을 다시 정의하는 것과 같이 종종 사용되는 함수입니다.ls즐겨찾기 옵션을 포함합니다.

신뢰할 수 없고 을 다루는 걱정하는 것이 안전하다고 생각합니다.unalias또는unset아면니있, 문에어서제그,있,while,do - 가 없습니다... - 재되의는것되문않지습다니가제은정▁...다않니습.....

기능이 본래의 의미와 행동을 갖기 위해 의존해야 하는 것이 있습니다 - 그것을 피할 방법은 없습니다.
POSIX와 유사한 셸은 내장된 언어 키워드의 재정의를 허용하며 심지어 언어 키워드도 본질적으로 보안 위험입니다(그리고 편집증적 코드를 작성하는 것은 일반적으로 어렵습니다).

구체적으로 귀하의 우려 사항을 해결하기 위해:

은 이기은다의니다존합에 합니다.unalias그리고.unset그들의 본래의 의미를 갖는.동작을 변경하는 방식으로 셸 함수로 재정의하는 것은 문제가 될 수 있습니다. 명령 이름(예: 일부)을 따옴표로 묶기 때문별칭으로 재정의하는 것은 문제가 되지 않습니다.\unalias 별칭을 합니다. 별칭을 무시합니다.

그러나 견적은 셸 키워드에 대한 옵션이 아닙니다.while,for,if,do...) 및 셸 키워드가 셸 함수보다 우선하지만,bash그리고.zsh우선 높기 때문에 에 대한 하려면 를 해야 .unalias그들의 이름으로 (비록 공격적이지만). bash셸(스크립트 등) 별칭은 기본적으로 확장되지 않습니다.shopt -s expand_aliases를 먼저 명시적으로 호출합니다.

확실하게 하기 위해unalias- 의미가 에 - 원본의있 - 가로므사합니다야용을 해야 합니다.\unset 먼그것대해에그, 필니다요합은것저▁that다▁on.unset본래의 의미는 다음과 같습니다.

unset내장된 셸이므로 이를 호출하려면 셸 자체가 함수로 재정의되지 않도록 해야 합니다.따옴표를 사용하여 별칭 양식을 바이패스할 수 있지만 셸 함수 양식 - 캐치 22는 바이패스할 수 없습니다.

그러므로, 당신이 의지할 수 없는 한.unset원래의 의미를 갖는다는 것은, 제가 아는 바로는, 모든 악의적인 재정의로부터 방어할 수 있는 보장된 방법이 없습니다.

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"))/..

이것은 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
    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##*/}"
)}

참로모것은cd그리고.set일은 하위 셸에서 발생합니다.

사용해 보십시오.

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

지난 몇 년간 이런 일을 여러 번 겪었고, 이번에는 OSX와 Linux에서 사용할 수 있는 순수 bash 휴대용 버전이 필요했기 때문에 다음과 같이 썼습니다.

라이브 버전은 다음과 같습니다.

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

Mac 비호환성 문제를 해결하기 위해 다음과 같은 방법을 생각해 냈습니다.

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

우수하지는 않지만 교차 운영 체제

여기서 저는 현재 잘 작동하고 있는 답변에 대해 크로스 플랫폼(적어도 Linux 및 macOS) 솔루션이라고 생각하는 것을 제시합니다.

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"
}

여기 macOS(전용) 솔루션이 있습니다.원래 질문에 더 적합할 수 있습니다.

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
}

대답은 Bash입니다. 어떻게 심볼릭 링크의 실제 경로를 얻을있을까요?

하지만 간단히 말해서 대본에 매우 유용합니다.

script_home=$( dirname $(realpath "$0") )
echo Original script home: $script_home

이는 GNU 코어 유틸리티의 일부로, Linux 시스템에서 사용하기에 적합합니다.

모든 것을 테스트하기 위해 symlink를 /home/test2/에 넣고 몇 가지 추가 사항을 수정한 후 루트 디렉토리에서 실행/호출합니다.

/$ /home/test2/symlink
/home/test
Original script home: /home/test

어디에

Original script is: /home/test/realscript.sh
Called script is: /home/test2/symlink

내2센. 이 함수는 이함와 POSIX 환호대소모다포다를 포함할 수 .->하지만 새 줄이나 탭이 포함된 파일 이름으로 작동하지 않습니다.ls일반적으로 그것들에 문제가 있습니다.

resolve_symlink() {
  test -L "$1" && ls -l "$1" | awk -v SYMLINK="$1" '{ SL=(SYMLINK)" -> "; i=index($0, SL); s=substr($0, i+length(SL)); print s }'
}

은 여서해은책결라고 합니다.file제공된 심볼릭 링크의 대상만 출력하는 사용자 지정 마법 파일을 포함하는 명령입니다.

이것은 Bash 3.2.57에서 테스트한 최고의 솔루션입니다.

# Read a path (similar to `readlink`) recursively, until the physical path without any links (like `cd -P`) is found.
# Accepts any existing path, prints its physical path and exits `0`, exits `1` if some contained links don't exist.
# Motivation: `${BASH_SOURCE[0]}` often contains links; using it directly to extract your project's path may fail.
#
# Example: Safely `source` a file located relative to the current script
#
#     source "$(dirname "$(rreadlink "${BASH_SOURCE[0]}")")/relative/script.sh"
#Inspiration: https://stackoverflow.com/a/51089005/6307827
rreadlink () {
    declare p="$1" d l
    while :; do
        d="$(cd -P "$(dirname "$p")" && pwd)" || return $? #absolute path without symlinks
        p="$d/$(basename "$p")"
        if [ -h "$p" ]; then
            l="$(readlink "$p")" || break

            #A link must be resolved from its fully resolved parent dir.
            d="$(cd "$d" && cd -P "$(dirname "$l")" && pwd)" || return $?
            p="$d/$(basename "$l")"
        else
            break
        fi
    done
    printf '%s\n' "$p"
}

언급URL : https://stackoverflow.com/questions/7665/how-to-resolve-symbolic-links-in-a-shell-script

반응형