주어진 상대 경로를 검색하는 방법


159

상대 경로가 주어진 절대 경로를 검색하는 명령이 있습니까?

예를 들어 $ line에 dir에있는 각 파일의 절대 경로를 포함 시키려고합니다. ./etc/

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


1
중복되지는 않지만 비슷 함
mpapis


지금까지 나열된 것보다 훨씬 더 나은 해결책은 여기에 상대 경로를 변환하는 방법-절대 경로를 유닉스로 변환하는 방법
Daniel Genin

답변:


66

사용하다:

find "$(pwd)"/ -type f

모든 파일을 얻거나

echo "$(pwd)/$line"

전체 경로 표시 (상대 경로가 중요한 경우)


2
찾기에서 상대 경로를 지정하면 어떻게됩니까?
nubme

17
질문에 대한 코멘트로 링크를 참조하십시오. 가장 좋은 방법은 아마도 'readlink -f $ line'입니다.
mpapis

3
$(pwd)대신에 왜 사용 $PWD합니까? (예, 저는 pwd내장 된 것입니다)
Adam Katz

178

시도하십시오 realpath.

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

심볼릭 링크가 확장되지 않도록하려면을 사용하십시오 realpath -s.

대답은 " 파일의 절대 경로를 인쇄하는 bash / fish 명령 "에서 나옵니다 .


11
realpathMac에서 사용할 수없는 것 같습니다 (OS X 10.11 "El Capitan"). :-(
Laryx Decidua

realpathCentOS 6에서도 사용할 수없는 것 같습니다
user5359531

6
osx에, brew install coreutils가져올 것이다realpath
Kevin Chen

내 우분투 18.04에 realpath이미 있습니다. 별도로 설치할 필요가 없었습니다.
Acumenus

놀랍게도 realpathWindows 용 Git에서 사용할 수 있습니다 (적어도 저에게는).
Andrew Keeton

104

coreutils 패키지를 설치 한 경우 일반적으로 readlink -f relative_file_name절대 패키지 를 검색하기 위해 사용할 수 있습니다 (모든 심볼릭 링크가 해결됨)


3
이 동작은 사용자가 요청한 것과 약간 다르며 경로의 어느 곳에서나 재귀 적 심볼릭 링크를 따르고 해결합니다. 경우에 따라 원하지 않을 수도 있습니다.
ffledgling

1
@BradPeabody homebrew에서 coreutils를 설치하면 Mac에서 작동 brew install coreutils합니다. 그러나 실행 파일 앞에 ag가 붙습니다.greadlink -f relative_file_name
Miguel Isla

2
readlink (1)의 매뉴얼 페이지에 설명의 첫 문장이 있습니다. "참고 realpath (1)은 정규화 기능에 사용하는 기본 명령입니다."
josch 2016 년

1
-f 대신 -e를 사용하여 파일 / 디렉토리가 존재하는지 여부를 확인할 수 있습니다.
Iceman

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

UPD 몇 가지 설명

  1. 이 스크립트는 상대 경로를 인수로 얻습니다. "$1"
  2. 그런 다음 해당 경로의 dirname 부분을 얻습니다 (dir 또는 file을이 스크립트에 전달할 수 있음).dirname "$1"
  3. 그런 다음 cd "$(dirname "$1")이 상대 디렉토리로 들어가서 pwd쉘 명령 을 실행하여 절대 경로를 얻습니다.
  4. 그런 다음 절대 경로에 기본 이름 을 추가 합니다.$(basename "$1")
  5. 마지막 단계는 우리로 echo그것을

8
이 답변은 최고의 Bash 관용구를 사용합니다
Rondo

2
readlink는 리눅스를위한 간단한 솔루션이지만이 솔루션은 OSX에서도 작동하므로 +1
thetoolman

1
이 스크립트는 것과 동일하지 않습니다 realpath또는 readlink -f않습니다. 예를 들어 마지막 구성 요소가 심볼릭 링크 인 경로에서는 작동하지 않습니다.
josch 2016 년

2
@ josch : 질문은 symlink 해결에 관한 것이 아닙니다. 그러나 그렇게하려면 다음과 같은 -P옵션을 제공 할 수 있습니다 pwd.echo "$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")"
Eugen Konkov

4
나는 대답을 좋아하지만 사용자가 디렉토리에 cd 할 수있는 경우에만 작동합니다. 항상 가능하지는 않습니다.
Matthias B

34

가치있는 것에 대해, 나는 선정 된 답변에 투표했지만 해결책을 공유하고 싶었습니다. 단점은 Linux뿐입니다 .Stack overflow에 오기 전에 OSX와 동등한 것을 찾으려고 약 5 분이 걸렸습니다. 그래도 확실합니다.

Linux readlink -e에서는와 함께 사용할 수 있습니다 dirname.

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

수확량

/etc/

그런 다음 dirname자매 를 사용 basename하여 파일 이름을 가져옵니다.

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

수확량

passwd

다 합쳐서 ..

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

수확량

/etc/passwd

디렉토리를 타겟팅하는 경우 안전 basename하고 아무것도 반환하지 않으며 최종 출력에서 ​​이중 슬래시로 끝납니다.


와 우수한 입장 dirname , readlink그리고 basename. 이를 통해 목표가 아닌 기호 링크의 절대 경로를 얻을 수있었습니다.
kevinarpe

심볼릭 링크의 경로를 반환하려고 할 때 작동하지 않습니다 (방금해야합니다 ...).
Tomáš Zato-Reinstate Monica

존재하지 않는 경로의 절대 경로를 어떻게 찾을 수 있습니까?
신디사이저

@synthesizerpatel 아주 쉽게 생각했을 것이다. 나는에있어 경우에 /home/GKFX나는 입력 touch newfileI 입력 키를 누르기 전에 당신은 내 말 것을 해결할 수있다 "생성 / 홈 / GKFX / newfile에"아직 존재하지 않는 파일에 대한 절대 경로이다.
GKFX

25

나는 이것이 가장 휴대용이라고 생각합니다.

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

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


3
다시 CD를 다시 넣을 필요가 없습니다. stackoverflow.com/a/21188136/1504556을 참조하십시오 . 이 페이지의 가장 좋은 답변은 IMHO입니다. 관심있는 사람들을 위해 링크는 이 솔루션이 작동 하는 이유에 대한 설명을 제공합니다.
peterh

이것은 이식성 dirname이 뛰어나지 않으며 GNU 핵심 유틸리티입니다.
einpoklum 2016 년

@einpoklum dirname은 POSIX 표준 유틸리티입니다. pubs.opengroup.org/onlinepubs/9699919799/utilities/dirname.html
Ernest A

세상에, 고마워 나는 ${1##*/}하루 동안 사용하는 버전을 수정하려고 노력 했으며 이제 휴지통을 휴지통으로 바꿨 basename "$1"으므로 마침내 /로 끝나는 경로를 올바르게 처리하는 것 같습니다.
l3l_aze

NB, 이것은 끝나는 길로 옳은 일을하지 않습니다../..
Alex Coventry

16

realpath 아마도 최고 일 것입니다

그러나 ...

초기 질문은 시작하기에 매우 혼란 스러웠으며, 언급 된 질문과 관련이없는 예가 있습니다.

선택한 답변은 실제로 제목의 모든 질문이 아니라 주어진 예제에 답변합니다. 첫 번째 명령은 그 대답입니다 (정말입니까? 의심 스럽습니다). '/'없이도 잘 할 수 있습니다. 그리고 두 번째 명령이 무엇을하는지 보지 못했습니다.

몇 가지 문제가 혼합되어 있습니다.

  • 상대 경로 이름을 절대 경로로 변경합니다. ( 일반적으로와 같은 명령을 실행하는 경우 파일이 실제로 작성되기 전에 touch foo/bar경로 이름이 foo/bar있어야하며 계산에 사용되어야합니다. )

  • 경로상의 심볼릭 링크 (symlink)로 인해 동일한 파일 (또는 잠재적 파일)을 나타내는 몇 개의 절대 경로 이름이있을 수 있지만 다른 이유로 인해 장치가 읽기 전용으로 두 번 마운트 될 수 있습니다. 그러한 심볼릭 링크를 명시 적으로 해결하거나 원하지 않을 수 있습니다.

  • 심볼릭 링크가 아닌 파일 또는 이름에 대한 심볼릭 링크의 끝에 도달 이는 수행 방법에 따라 절대 경로 이름을 생성하거나 생성하지 않을 수 있습니다. 그리고 그것을 절대 경로 이름으로 해결하거나 원하지 않을 수 있습니다.

readlink foo옵션이없는 명령 은 인수가있는 경우에만 답변을 제공합니다foo 가 기호 링크 인 하며 해당 응답은 해당 심볼릭 링크의 값입니다. 다른 링크는 따르지 않습니다. 대답은 상대 경로 일 수 있습니다. symlink 인수의 값이 무엇이든간에.

하나, readlink 모든 파일에 대해 작동하는 옵션 (-f -e 또는 -m)이 있으며 실제로 인수로 표시된 파일에 대한 하나의 절대 경로 이름 (심볼 링크가없는 경로 이름)을 제공합니다.

이것은 경로의 중간 심볼릭 링크를 해결하지 않고 절대 경로 이름을 사용하고자 할 수도 있지만 심볼릭 링크가 아닌 모든 것에 잘 작동합니다. 이것은 명령에 의해 수행됩니다realpath -s foo

symlink 인수의 경우 readlink해당 옵션을 사용하면 인수의 절대 경로에있는 모든 symlink가 다시 해결되지만 인수 값에 따라 발생할 수있는 모든 symlink도 포함됩니다. 심볼릭 링크 자체에 대한 링크가 아닌 경로에 대한 절대 경로를 원한다면 원하지 않을 수도 있습니다. 다시 한 번 foo심볼릭 링크 인 경우 realpath -s foo인수로 제공된 심볼릭 링크를 포함하여 심볼릭 링크를 해결하지 않고 절대 경로를 얻습니다.

-s옵션이 없으면 단순히 링크의 값을 읽는 것 외에 몇 가지 다른 것을 제외 realpath하고는와 거의 동일 readlink합니다. readlink옵션이있는 이유 가 분명하지 않아서 바람직하지 않은 중복성을 realpath만듭니다.

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

결론 : realpath최소한 여기에 요청 된 용도에 대해 가장 유연하게 사용할 수있는 최상의 명령입니다.


10

내가 가장 좋아하는 솔루션이었다 사람 @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
}

7

Eugen의 대답은 저에게 효과적이지 않았지만 이것은 효과가있었습니다.

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

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


주의 : 그것은 스크립트입니다. 여기서 $ 1이 첫 번째 논거
Eugen Konkov

5

가장 좋은 솔루션 인 imho는 https://stackoverflow.com/a/3373298/9724628에 게시 된 솔루션 입니다.

파이썬이 작동해야하지만 모든 경우 또는 대부분의 최신 사례를 다루고 휴대 성이 뛰어난 솔루션 인 것 같습니다.

  1. 심볼릭 링크 해결 :
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

3

의 경우 find검색 할 절대 경로를 지정하는 것이 가장 쉬운 방법입니다. 예 :

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

3

당신은 어느 쪽도있다 맥 OS X에 bash에 사용하는 경우 realpath 존재하지이나 그 readlink를가 절대 경로를 인쇄 할 수 있습니다, 당신은 그것을 인쇄 선택하지만 코드에 자신의 버전이있을 수 있습니다. 내 구현은 다음과 같습니다.

(순수한 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

1

find $PWD또는 bash를 제외하고 그들이 말한 find ~+것이 조금 더 편리합니다.


1

@ ernest-a의 답변과 비슷하지만 $OLDPWD새로운 기능에 영향을 주거나 정의 하지 않고 서브 쉘을 실행할 수 있습니다(cd <path>; pwd)

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


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

3
이 코드 스 니펫에 대해 약간의 단기적인 도움을 제공 할 수 있습니다. 적절한 설명 이것이 문제에 대한 좋은 해결책 인지 보여줌으로써 장기적인 가치를 크게 향상시킬 것이며, 다른 비슷한 질문을 가진 미래 독자들에게 더 유용 할 것입니다. 제발 편집 당신이 만든 가정 등 일부 설명을 추가 할 답변을.
Toby Speight

1

@ ernest-a의 오히려 좋은 버전 개선 :

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

제대로 경로의 마지막 요소 인 케이스, 거래 ..하는 경우 "$(pwd)/$(basename "$1")"에 @ 어니스트-A의 대답은로를 통해 올 것이다 accurate_sub_path/spurious_subdirectory/...


0

상대 경로를 포함하는 변수를 절대 경로로 변환하려면 다음과 같이 작동하십시오.

   dir=`cd "$dir"`

"cd"는 하위 디렉토리에서 실행되므로 작업 디렉토리를 변경하지 않고 에코됩니다.


2
bash-4.3-p46에서는 작동하지 않습니다. 셸을 실행하면 빈 줄이 인쇄됩니다.dir=`cd ".."` && echo $dir
Michael

0

이것은 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")" "${?}"

0

상대 경로 $ line에 bash 문자열 대체를 사용할 수 있습니다.

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

기본 문자열 앞쪽 대체는 공식
$ {string / # substring / replacement}
를 따릅니다 . https://www.tldp.org/LDP/abs/html/string-manipulation.html

\문자가를 부정 /우리는 우리가 찾기 / 대체하는 문자열의 일부가 될하고자 할 때.


0

Mac OS Catalina, Ubuntu 16 및 Centos 7 사이에서 깔끔하게 이식 가능한 솔루션을 찾을 수 없었기 때문에 파이썬 인라인으로 작업하기로 결정했으며 내 bash 스크립트에서 잘 작동했습니다.

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

to_abs_path "/some_path/../secrets"
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.