programing

지정된 상대 경로 절대 경로 검색 방법

muds 2023. 4. 11. 22:38
반응형

지정된 상대 경로 절대 경로 검색 방법

상대 패스가 지정된 절대 패스를 취득하는 명령어가 있습니까?

를 들어 $각 파일의 절대 ./etc/

find ./ -type f | while read line; do
   echo $line
done

★★를 해 보세요.realpath

~ $ sudo apt-get install realpath  # may already be installed
~ $ realpath .bashrc
/home/username/.bashrc

전개하지 , 「」를 합니다.realpath -s.

정답은 "bash/fish 명령으로 파일에 대한 절대 경로를 인쇄합니다."에서 나옵니다.

되어 있는 으로 coreutils를 사용할 수 .readlink -f relative_file_nameone이 해결된 을 심볼릭이 해결된 상태)

#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"

UPD 설명

  1. 는 인수로 ."$1"
  2. 다음으로 경로의 dirname 부분을 가져옵니다(이 스크립트에 dir 또는 파일 중 하나를 전달할 수 있습니다). dirname "$1"
  3. 우리 ★★★★★★★★★★★★★★★★★★★.cd "$(dirname "$1")하여 "dir"를 실행하여 .pwd 명령어 셸 " " "
  4. 그런 다음 절대 경로에 기본 이름을 추가합니다.$(basename "$1")
  5. 로서 우리는 【【【계】【 as】echo

용도:

find "$(pwd)"/ -type f

모든 파일을 가져오거나

echo "$(pwd)/$line"

전체 경로를 표시합니다(상대 경로가 중요한 경우).

중요한 건, 저는 뽑힌 답변에 투표했지만, 해결책을 공유하고 싶었습니다.단점은 Linux뿐이라는 것입니다.Stack overflow에 도달하기 전에 약 5분 동안 동등한 OSX를 찾으려고 했습니다.밖에 분명히 있을 거야

를 사용할 수 .readlink -e와와 with 와 함께dirname.

$(dirname $(readlink -e ../../../../etc/passwd))

수율

/etc/

에 리고 and and and and를 사용합니다.dirname여동생인 의 '는basename

$(basename ../../../../../passwd)

수율

passwd

모두 합쳐서..

F=../../../../../etc/passwd
echo "$(dirname $(readlink -e $F))/$(basename $F)"

수율

/etc/passwd

를 대상으로basename아무것도 반환되지 않고 최종 출력에 이중 슬래시가 표시됩니다.

이게 가장 휴대성이 좋은 것 같아요.

abspath() {                                               
    cd "$(dirname "$1")"
    printf "%s/%s\n" "$(pwd)" "$(basename "$1")"
    cd "$OLDPWD"
}

경로가 존재하지 않으면 실패합니다.

realpath 좋을 것이다

그렇지만.....

첫 번째 질문은 처음에 매우 혼란스러웠습니다. 앞서 말한 질문과 관련이 없는 예시를 들 수 있습니다.

선택된 답변은 실제로 주어진 예제에 대한 답변이지만 제목에 있는 질문은 전혀 답변하지 않습니다.첫 번째 명령어는 그 대답입니다(진짜입니까?).'/'가 없어도 충분할 것 같습니다.그리고 두 번째 명령어가 무엇을 하는지 알 수 없습니다.

몇 가지 문제가 혼재하고 있습니다.

  • 상대 경로 이름을 절대 경로 이름으로 변경하는 경우(일반적으로 파일을 실제로 작성하기 전에 경로 이름이 존재해야 하며 계산에 사용되어야 합니다).

  • 같은 파일(또는 잠재적인 파일)을 나타내는 절대 패스명이 여러 개 있을 수 있습니다.특히 패스상의 심볼릭링크(symbolic links)가 원인이지만 다른 이유(디바이스는 읽기 전용으로2회 마운트되는 경우가 있습니다).이러한 심볼링크를 해결할 수도 있고 아닐 수도 있다.

  • 심볼릭 링크 체인의 끝에 도달하여 링크되지 않은 파일 또는 이름으로 이동합니다.이 경우 실행 방법에 따라 절대 경로 이름이 생성되거나 생성되지 않을 수 있습니다.절대 경로명으로 해결할 수도 있고 아닐 수도 있습니다.

" " "readlink foo는 그 인수가 「그렇다」인 합니다.foo는 심볼릭 링크이며, 그 답은 그 심볼링크의 값입니다.하다argument.symlink 될 수.

★★★★★★★★★★★★★★.readlink에는 모든 파일에 대해 기능하는 옵션(-f -e 또는 -m)이 있으며 인수로 실제로 나타나는 파일에 대해 1개의 절대 경로 이름(심볼 링크가 없는 것)을 지정합니다.

경로의 중간 심볼링크를 해결하지 않고 절대 경로 이름을 사용할 수도 있지만 심볼링크가 아닌 경우에는 이 방법이 잘 작동합니다.로 할 수 있습니다.realpath -s foo

인수의 symlink " " 입니다.readlink옵션을 사용하면 인수에 대한 절대 경로 상의 모든 심볼링크가 다시 해결되지만 인수 값을 따라가면 발생할 수 있는 모든 심볼링크가 포함됩니다.링크할 수 있는 것이 아니라 인수 심볼링크 자체에 대한 절대 경로를 원하는 경우에는 이 경로를 사용하지 않을 수 있습니다. 한 번 말하면foorealpath -s foo는 인수로 지정된 링크를 포함하여 심볼링크를 해결하지 않고 절대 경로를 가져옵니다.

-s 「」,realpath 행동하다readlink단, 링크의 값을 단순히 읽는 것 외에 다른 몇 가지 사항을 제외합니다. 그런지 .readlink, 「이러한 」이나 「이러한 용장성」을 것이 않은 용장성은 「이러한 용장성」으로 되어 있습니다.realpath.

웹 탐색은 시스템 간에 약간의 차이가 있을 수 있다는 점을 제외하고 더 이상 많은 것을 의미하지는 않습니다.

: 론 :realpath적어도 여기서 요구하는 사용에는 가장 유연하게 사용할 수 있는 최적의 명령어입니다.

제가 가장 좋아하는 솔루션은 @EugenKonkov의 솔루션이었습니다.그것은 다른 유틸리티(coreutils 패키지)의 존재를 의미하는 것이 아니기 때문입니다.

그러나 상대 경로 "."와 "..."에 대해서는 실패했기 때문에, 이 특별한 경우를 다루는 약간 개선된 버전을 소개합니다.

가 사용 합니다.cd합니다.

#! /bin/sh

# Takes a path argument and returns it as an absolute path. 
# No-op if the path is already absolute.
function to-abs-path {
    local target="$1"

    if [ "$target" == "." ]; then
        echo "$(pwd)"
    elif [ "$target" == ".." ]; then
        echo "$(dirname "$(pwd)")"
    else
        echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
    fi
}

Eugen의 대답은 내게는 잘 먹히지 않았지만, 이것은 효과가 있었다.

    absolute="$(cd $(dirname \"$file\"); pwd)/$(basename \"$file\")"

참고로 현재 작업 디렉토리는 영향을 받지 않습니다.

@ernest-a의 비교적 좋은 버전에 대한 개선점:

absolute_path() {
    cd "$(dirname "$1")"
    case $(basename $1) in
        ..) echo "$(dirname $(pwd))";;
        .)  echo "$(pwd)";;
        *)  echo "$(pwd)/$(basename $1)";;
    esac
}

이는 경로의 마지막 요소가 다음과 같은 경우에 올바르게 대처합니다...이 경우 )는"$(pwd)/$(basename "$1")"은 @hymp-a로 .accurate_sub_path/spurious_subdirectory/...

최고의 솔루션인 imho는 https://stackoverflow.com/a/3373298/9724628에 게시된 것입니다.

Python이 작동하려면 Python이 필요하지만, 엣지 케이스의 전체 또는 대부분을 커버하는 것으로 보여 매우 휴대성이 좋은 솔루션입니다.

  1. symbolinks 해결 시:
python -c "import os,sys; print(os.path.realpath(sys.argv[1]))" path/to/file
  1. 또는 없는 경우:
python -c "import os,sys; print(os.path.abspath(sys.argv[1]))" path/to/file

find검색할 절대 경로를 지정하는 것이 가장 쉬울 것입니다. 예를 들어 다음과 같습니다.

find /etc
find `pwd`/subdir_of_current_dir/ -type f

실제 경로가 존재하지 않거나 읽기 링크가 절대 경로를 인쇄할 수 없는 Mac OS X에서 bash를 사용하는 경우, 자신의 버전을 코드화하여 인쇄해야 할 수도 있습니다.실장은 다음과 같습니다.

(순수한 bash)

abspath(){
  local thePath
  if [[ ! "$1" =~ ^/ ]];then
    thePath="$PWD/$1"
  else
    thePath="$1"
  fi
  echo "$thePath"|(
  IFS=/
  read -a parr
  declare -a outp
  for i in "${parr[@]}";do
    case "$i" in
    ''|.) continue ;;
    ..)
      len=${#outp[@]}
      if ((len==0));then
        continue
      else
        unset outp[$((len-1))] 
      fi
      ;;
    *)
      len=${#outp[@]}
      outp[$len]="$i"
      ;;
    esac
  done
  echo /"${outp[*]}"
)
}

(가우크 사용)

abspath_gawk() {
    if [[ -n "$1" ]];then
        echo $1|gawk '{
            if(substr($0,1,1) != "/"){
                path = ENVIRON["PWD"]"/"$0
            } else path = $0
            split(path, a, "/")
            n = asorti(a, b,"@ind_num_asc")
            for(i in a){
                if(a[i]=="" || a[i]=="."){
                    delete a[i]
                }
            }
            n = asorti(a, b, "@ind_num_asc")
            m = 0
            while(m!=n){
                m = n
                for(i=1;i<=n;i++){
                    if(a[b[i]]==".."){
                        if(b[i-1] in a){
                            delete a[b[i-1]]
                            delete a[b[i]]
                            n = asorti(a, b, "@ind_num_asc")
                            break
                        } else exit 1
                    }
                }
            }
            n = asorti(a, b, "@ind_num_asc")
            if(n==0){
                printf "/"
            } else {
                for(i=1;i<=n;i++){
                    printf "/"a[b[i]]
                }
            }
        }'
    fi
}

(순수 bsd awk)

#!/usr/bin/env awk -f
function abspath(path,    i,j,n,a,b,back,out){
  if(substr(path,1,1) != "/"){
    path = ENVIRON["PWD"]"/"path
  }
  split(path, a, "/")
  n = length(a)
  for(i=1;i<=n;i++){
    if(a[i]==""||a[i]=="."){
      continue
    }
    a[++j]=a[i]
  }
  for(i=j+1;i<=n;i++){
    delete a[i]
  }
  j=0
  for(i=length(a);i>=1;i--){
    if(back==0){
      if(a[i]==".."){
        back++
        continue
      } else {
        b[++j]=a[i]
      }
    } else {
      if(a[i]==".."){
        back++
        continue
      } else {
        back--
        continue
      }
    }
  }
  if(length(b)==0){
    return "/"
  } else {
    for(i=length(b);i>=1;i--){
      out=out"/"b[i]
    }
    return out
  }
}

BEGIN{
  if(ARGC>1){
    for(k=1;k<ARGC;k++){
      print abspath(ARGV[k])
    }
    exit
  }
}
{
  print abspath($0)
}

예:

$ abspath I/am/.//..//the/./god/../of///.././war
/Users/leon/I/the/war

@ @ernest-a는 영향을 주지 .$OLDPWD 서브셸을 할 수 을 정의합니다.(cd <path>; pwd)

$ pwd
/etc/apache2
$ cd ../cups 
$ cd -
/etc/apache2
$ (cd ~/..; pwd)
/Users
$ cd -
/etc/cups

Mac OS Catalina, Ubuntu 16, Centos 7 사이에서 깔끔하게 휴대할 수 있는 솔루션을 찾을 수 없었기 때문에 python inline으로 하기로 결정했고 bash 스크립트에서 잘 작동했습니다.

to_abs_path() {
  python -c "import os; print os.path.abspath('$1')"
}

to_abs_path "/some_path/../secrets"

프로그램을 설치할 필요가 없기 때문에, 나는 Eugen Konkov의 답변이 최고라는 을 알았다.그러나 존재하지 않는 디렉토리에 대해서는 실패합니다.

존재하지 않는 디렉토리에 대해 기능하는 함수를 작성했습니다.

function getRealPath()
{
    local -i traversals=0
    currentDir="$1"
    basename=''
    while :; do
        [[ "$currentDir" == '.' ]] && { echo "$1"; return 1; }
        [[ $traversals -eq 0 ]] && pwd=$(cd "$currentDir" 2>&1 && pwd) && { echo "$pwd/$basename"; return 0; }
        currentBasename="$(basename "$currentDir")"
        currentDir="$(dirname "$currentDir")"
        [[ "$currentBasename" == '..' ]] && (( ++traversals )) || { [[ traversals -gt 0 ]] && (( traversals-- )) || basename="$currentBasename/$basename"; }
    done
}

하지 않는 합니다.dirnamecd 디렉토리와 함께 "Directory"에 의해 됩니다.dirname.

것, ★★★★★★★★★★★★★★★★★★★★★★★★ 제외find $PWD또는 (bash로)find ~+조금 더 편리합니다.

상대 경로가 디렉토리 경로인 경우 mine을 사용해 보십시오.

absPath=$(pushd ../SOME_RELATIVE_PATH_TO_Directory > /dev/null && pwd && popd > /dev/null)

echo $absPath

임의의 상대 경로 $line에 bash 문자열 치환을 사용할 수 있습니다.

line=$(echo ${line/#..\//`cd ..; pwd`\/})
line=$(echo ${line/#.\//`pwd`\/})
echo $line

은 공식에 .
}${cring/#cring/replacement}
여기서 잘 설명하겠습니다.https://www.tldp.org/LDP/abs/html/string-manipulation.html

\한 것입니다./검색/바꾸는 문자열의 일부로 만들고 싶을 때 사용합니다.

여기에서는 쉘과 POSIX만을 를 완전히 하기 위해 할 수 다소 .readlink★★★★★★★★★★★★★★★★★★:

canonicalize_path() {
    (
        FILEPATH="$1"
        for _ in 1 2 3 4 5 6 7 8;  # Maximum symlink recursion depth
        do
            cd -L "`case "${FILEPATH}" in */*) echo "${FILEPATH%/*}";; *) echo ".";; esac`/"  # cd $(dirname)
            if ! FILEPATH="$(readlink "${FILEPATH##*/}" || ( echo "${FILEPATH##*/}" && false ) )";
            then
                break
            fi
        done
        cd -P "." || return $?
        echo "$(pwd)/${FILEPATH}"
    )
}

참조된 파일이 존재하지 않는 경우 최종 파일명으로 이어지는 디렉토리 경로만 해결됩니다. 하지 않는 cd에러가 반환됩니다.GNU/입니다.readlink -f명령어를 사용합니다.

bash을 bash/zsh로만 .{1..8}또는 이와 유사합니다. 전 4.총.인 「」)를 합니다.[ -L "${FILEPATH}" ]이 상태를 할 수 .

이 코드는 기능 및 서브셸 래퍼를 제거하는 것만으로 현재 작업 디렉토리가 파일 시스템에서 실행되는 스크립트의 위치(셸 스크립트의 일반적인 요건)와 일치하도록 하기 위해 쉽게 재사용할 수 있습니다.

FILEPATH="$0"
for _ in 1 2 3 4 5 6 7 8;  # Maximum symlink recursion depth
do
    cd -L "`case "${FILEPATH}" in */*) echo "${FILEPATH%/*}";; *) echo ".";; esac`/"  # cd $(dirname)
    if ! FILEPATH="$(readlink "${FILEPATH##*/}" || ( echo "${FILEPATH##*/}" && false ) )";
    then
        break
    fi
done
cd -P "."
FILEPATH="$(pwd)/${FILEPATH}"

블루프:

cd $relative_path ; pwd

POSIX에 준거하고 있기 때문에, 어느 플랫폼에서도 동작할 수 있다고 생각합니다.

물론 스크립트 작성은 가능하지만, 내용을 세분화하면 특정 사용 사례를 쉽게 이해하거나 수정할 수 있을 것으로 생각합니다.

하시면 됩니다.which,locate,find풀패스든 뭐든.

x=your_file_name

$ x="nvi" 

file .

$ file -h `which $x`
/usr/local/bin/nvi: symbolic link to ../Cellar/nvi/1.81.6_5/bin/nvi

그런 다음 출력을 조금 더 주입하여 "완전한" 상대 경로를 얻습니다.
이 예에서는 중간 부분만 제거하면 됩니다.

대문자 Y와 소문자 x에 주의해 주세요.아마도 이것을 하는 더 깨끗한 방법이 있을 것이다.

$ Y=$(file -h `which $x` | sed "s/$x: symbolic link to //")


$ echo $Y
/usr/local/bin/../Cellar/nvi/1.81.6_5/bin/nvi

「」를 사용합니다.dirname을 사용하다 cd그러면 이름이 스스로 깨끗해질 거야

$ cd `dirname $Y` ; pwd
/usr/local/Cellar/nvi/1.81.6_5/bin

그 때문에, 디렉토리를 「고스트 워크」해, 괄호/서브 셸로 모두 「고스트 워크」하는 낡은 UNIX 트릭으로 연결됩니다.그러면 작업이 완료되면 현재 디렉토리로 돌아갑니다.

완성도를 높이기 위해 실제 파일 이름을 끝에 붙일 수 있습니다.

ls보너스 포인트에 대해 절대 경로가 유효한지 확인합니다.

$ ( cd `dirname ${Y}` ; ls `pwd`/${x} )
/usr/local/Cellar/nvi/1.81.6_5/bin/nvi

★★★★★★★★★★★★★★★★★./usr/local/bin/nvi '아주변이야./usr/local/Cellar/nvi/1.81.6_5/bin/nvi

경로를 신속하게 "변환"하기 위한 간단한 예:

$ (cd /usr/local/bin/../Cellar/nvi/1.81.6_5/bin ; pwd)
/usr/local/Cellar/nvi/1.81.6_5/bin

https://pubs.opengroup.org/onlinepubs/9699919799/utilities/file.html https://pubs.opengroup.org/onlinepubs/9699919799/utilities/dirname.html

echo "mydir/doc/ mydir/usoe ./mydir/usm" |  awk '{ split($0,array," "); for(i in array){ system("cd "array[i]" && echo $PWD") } }'

위 스니펫에서는 awk를 사용하여 (파이프라인을 통해) 에코로부터 수신한 디렉토리의 문자열을 분할하고 배열을 작성합니다.

다음은 진행 상황을 단계별로 나열한 목록입니다.

  • 공백으로 구분된 디렉토리 목록이 awk로 파이핑됩니다.
  • awk는 파이핑된 텍스트를 공백별로 배열로 분할합니다.
  • awk는 어레이 내의 각 항목을 루프합니다(i)
  • awk는 awk system 명령을 사용하여 cli 명령을 실행합니다.
  • CLI 명령어는 디렉토리(cd)를 어레이 내의 항목 "i"로 지정된 경로로 변경한 후 환경 변수 $PWD를 사용하여 작업 디렉토리를 인쇄(에코)합니다.

CD를 사용하여 각 디렉토리로 이동한 후 $PWD 값을 인쇄하는 것은 OS가 절대 경로를 결정하는 작업을 수행하도록 하는 좋은 방법입니다.

상대경로를 포함하는 변수를 절대경로로 변환하는 경우 다음과 같이 동작합니다.

   dir=`cd "$dir"`

여기서 서브셸로 실행되기 때문에 "cd"는 작업 디렉토리를 변경하지 않고 에코됩니다.

은 다른를 들어, 른 solution른른른른른 from from from from from from from from from from from from from from from from from from from from from from from from. 예를 들어 다음과 같은 경우realpath에러 코드가 인스톨 되어 있지 않거나, 에러 코드가 붙어 종료하고 있기 때문에, 에러가 발생하고 있는 경우는, 패스가 올바르게 확립될 때까지 다음의 솔루션이 시행됩니다.

#!/bin/bash

function getabsolutepath() {
    local target;
    local changedir;
    local basedir;
    local firstattempt;

    target="${1}";
    if [ "$target" == "." ];
    then
        printf "%s" "$(pwd)";

    elif [ "$target" == ".." ];
    then
        printf "%s" "$(dirname "$(pwd)")";

    else
        changedir="$(dirname "${target}")" && basedir="$(basename "${target}")" && firstattempt="$(cd "${changedir}" && pwd)" && printf "%s/%s" "${firstattempt}" "${basedir}" && return 0;
        firstattempt="$(readlink -f "${target}")" && printf "%s" "${firstattempt}" && return 0;
        firstattempt="$(realpath "${target}")" && printf "%s" "${firstattempt}" && return 0;

        # If everything fails... TRHOW PYTHON ON IT!!!
        local fullpath;
        local pythoninterpreter;
        local pythonexecutables;
        local pythonlocations;

        pythoninterpreter="python";
        declare -a pythonlocations=("/usr/bin" "/bin");
        declare -a pythonexecutables=("python" "python2" "python3");

        for path in "${pythonlocations[@]}";
        do
            for executable in "${pythonexecutables[@]}";
            do
                fullpath="${path}/${executable}";

                if [[ -f "${fullpath}" ]];
                then
                    # printf "Found ${fullpath}\\n";
                    pythoninterpreter="${fullpath}";
                    break;
                fi;
            done;

            if [[ "${pythoninterpreter}" != "python" ]];
            then
                # printf "Breaking... ${pythoninterpreter}\\n"
                break;
            fi;
        done;

        firstattempt="$(${pythoninterpreter} -c "import os, sys; print( os.path.abspath( sys.argv[1] ) );" "${target}")" && printf "%s" "${firstattempt}" && return 0;
        # printf "Error: Could not determine the absolute path!\\n";
        return 1;
    fi
}

printf "\\nResults:\\n%s\\nExit: %s\\n" "$(getabsolutepath "./asdfasdf/ asdfasdf")" "${?}"

@EugenKonkov의 답변과 @HashChange의 답변기초하여, 저의 답변은 전자의 간결함과 대처법을 결합하였습니다.. ★★★★★★★★★★★★★★★★★」..후자의아래의 모든 옵션은 기본적인 명령어 언어 POSIX 표준에만 의존한다고 생각합니다.

「」를 사용합니다.dirname ★★★★★★★★★★★★★★★★★」basename , , , , , , , , , , , 가

absPathDirname()
{
    [ -d "${1}" ] && set -- "${1}" || set -- "`dirname "${1}"`" "/`basename "${1}"`"
    echo "`cd "${1}"; pwd`${2}";
}

「 」를 사용하지 dirname ★★★★★★★★★★★★★★★★★」basename또 선택지는 , , ㄴㄴㄴㄴㄴ다

absPathMinusD()
{
    [ -d "${1}" ] && set -- "${1}" || set -- "${1%${1##*/}}" "/${1##*/}"
    echo "`cd "${1:-.}"; pwd`${2}";
}

위의 두 가지 옵션 중 하나를 추천하고 나머지는 그냥 재미로...

Grep 버전:

absPathGrep()
{
    echo "`[ "${1##/*}" ] && echo "$1" | grep -Eo '^(.*/)?\.\.($|/)' | { read d && cd "$d"; echo "${PWD}/${1#$d}"; } || echo "$1"`"
}

"쉘의 제한된 RegEx로 수행할 수 있는 작업"의 흥미로운 예로서 다음과 같습니다.

absPathShellReplace()
{
    E="${1##*/}"; D="${E#$E${E#.}}"; DD="${D#$D${D#..}}"
    DIR="${1%$E}${E#$DD}"; FILE="${1#$DIR}"; SEP=${FILE:+/}
    echo "`cd "${DIR:-.}"; pwd`${SEP#$DIR}$FILE"
}

python 3을 사용한 이전 답변 업데이트

to_abs_path() {
  python -c "import os; print (os.path.abspath('$1'))"
}

허용하는

to_abs_path "./../some_file.txt"

언급URL : https://stackoverflow.com/questions/4175264/how-to-retrieve-absolute-path-given-relative

반응형