Göreli olarak verilen mutlak yol nasıl alınır


160

Göreli yol verildiğinde mutlak yolu almak için bir komut var mı?

Örneğin $ satır dir her dosyanın mutlak yolunu içeren istiyorum ./etc/

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


1
stright duplicate değil, ama benzer
mpapis


Şimdiye kadar listelenenlerden çok daha iyi bir çözüm, burada nasıl-dönüştürmek-göreceli-yol-mutlak-yol-unix
Daniel Genin

Yanıtlar:


67

kullanın:

find "$(pwd)"/ -type f

tüm dosyaları almak için veya

echo "$(pwd)/$line"

tam yolu görüntülemek için (göreli yol önemliyse)


2
Bulmak göreli bir yol belirtirseniz ne ??
nubme

17
sonra sorunuzun yorumuna yapılan bağlantılara bakın, en iyi yol muhtemelen 'readlink -f $ line'
mpapis

3
Neden $(pwd)yerine kullanılır $PWD? (evet, pwdyerleşik olduğunu biliyorum )
Adam Katz

179

Deneyin realpath.

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

Simgelerin genişlemesini önlemek için kullanın realpath -s.

Yanıt " bir dosyaya mutlak yol yazdırmak için bash / fish komutundan " gelir.


11
realpathMac'te mevcut görünmüyor (OS X 10.11 "El Capitan"). :-(
Laryx Decidua

realpathCentOS 6'da da mevcut görünmüyor
user5359531

6
osx, brew install coreutilsgetirecekrealpath
Kevin Chen

Ubuntu 18.04'ümde realpathzaten var. Ayrı olarak kurmak zorunda değildim.
Acumenus

Şaşırtıcı bir şekilde, realpathWindows için Git'te kullanılabilir (en azından benim için).
Andrew Keeton

104

Eğer coreutils paketini kurduysanız, genellikle readlink -f relative_file_namemutlak olanı almak için kullanabilirsiniz (tüm semboller çözülmüş olarak)


3
Bunun davranışı, kullanıcının sorduğundan biraz farklıdır, ayrıca yolun herhangi bir yerinde yinelemeli sembolik bağlantıları izler ve çözer. Bazı durumlarda bunu istemeyebilirsiniz.
16:28

1
@BradPeabody Homebrew'dan coreutils yüklerseniz bu bir Mac'te çalışır brew install coreutils. Ancak yürütülebilir ag tarafından eklenir:greadlink -f relative_file_name
Miguel Isla

2
Readlink (1) kılavuz sayfasının açıklamasının ilk cümlesine sahip olduğuna dikkat edin: "Not realpath (1), standartlaştırma işlevselliği için tercih edilen komuttur."
josch

1
Dosyanın / dizinin var olup olmadığını kontrol etmek için -f yerine -e kullanabilirsiniz
Iceman

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

UPD Bazı açıklamalar

  1. Bu komut dosyası bağımsız değişken olarak göreli yol al "$1"
  2. Sonra bu yolun dirname bölümünü alırız (dir veya dosyayı bu betiğe aktarabilirsiniz):dirname "$1"
  3. Sonra biz cd "$(dirname "$1")bu göreceli dir içine ve pwdkabuk komutunu çalıştırarak bunun için mutlak yol olsun
  4. Bundan sonra muten yola taban adı ekliyoruz :$(basename "$1")
  5. Son adım biz echoonu

8
Bu cevap en iyi Bash deyimini kullanır
Rondo

2
readlink linux için basit bir çözümdür, ancak bu çözüm OSX üzerinde de çalışır, bu yüzden +1
thetoolman

1
Bu komut dosyası neye realpathveya readlink -fyapmaya eşdeğer değildir . Örneğin, son bileşenin bir sembolik bağlantı olduğu yollarda çalışmaz.
josch

2
@josch: Soru, sembolik bağlantının çözülmesiyle ilgili değil. Ancak bunu yapmak istiyorsanız, komut verme -Pseçeneği sunabilirsiniz pwd:echo "$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")"
Eugen Konkov

4
Ben yanıtı seviyorum, ama sadece kullanıcı dizine cd izin verilirse çalışır. Bu her zaman mümkün olmayabilir.
Matthias B

34

Değeri için, alınan cevaba oy verdim, ancak bir çözümü paylaşmak istedim. Dezavantajı, sadece Linux - Stack overflow gelmeden önce OSX eşdeğerini bulmak için yaklaşık 5 dakika geçirdim. Eminim orada olsa.

Linux'ta readlink -ebirlikte kullanabilirsiniz dirname.

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

verim

/etc/

Ve sonra dosya adını almak için dirnamekız kardeşini kullanıyorsunbasename

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

verim

passwd

Hepsini bir araya getirmek..

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

verim

/etc/passwd

Bir dizini hedefliyorsanız güvende olursunuz, basenamehiçbir şey döndürmez ve son çıkışta çift eğik çizgi elde edersiniz.


Mükemmel ile giriş dirname, readlinkve basename. Bu, hedefine değil, sembolik bir bağlantının mutlak yolunu elde etmeme yardımcı oldu.
kevinarpe

(Sadece yapmam gereken ...) sembolik bağlantılara yol döndürmek istediğinizde çalışmaz.
Tomáš Zato - Monica'yı eski durumuna getir

Varolmayan bir yola giden mutlak yolu nasıl bulabilirdiniz?
synthesizerpatel

@synthesizerpatel Kolayca düşünürdüm; Ben varım eğer /home/GKFXben yazın touch newfileben girmek basmadan önce, sonra ne demek olduğunu işe yarayabilir, "oluşturmak / home / SLFS / yenidosya", henüz var olmayan bir dosyaya mutlak bir yol olduğu.
GKFX

25

Bu en taşınabilir olduğunu düşünüyorum:

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

Yol mevcut değilse başarısız olur.


3
Tekrar cd'ye gerek yok. Bkz. Stackoverflow.com/a/21188136/1504556 . Sizinki bu sayfadaki en iyi cevap IMHO. İlgilenenler için bağlantı, bu çözümün neden işe yaradığına dair bir açıklama verir .
peterh

Bu çok taşınabilir değil dirname, bir GNU çekirdek yardımcı programdır, inanıyorum tüm unixen için ortak değildir.
einpoklum

@ einpoklum dirnamebir POSIX standart yardımcı programıdır, buraya bakın: pubs.opengroup.org/onlinepubs/9699919799/utilities/dirname.html
Ernest A

Aman Tanrım, teşekkür ederim. Ben ${1##*/}şimdi bir gün için kullanılan sürümü düzeltmek için çalışıyorum , ve şimdi ben basename "$1"onunla o çöp yerine nihayet sonunda / yollarını düzgün görünüyor gibi görünüyor.
l3l_aze

Dikkat, bu biten bir yol ile doğru olanı yapmaz../..
Alex Coventry

16

realpath muhtemelen en iyisi

Fakat ...

İlk soru başlangıçta çok karışıktı, belirtildiği gibi soruyla zayıf ilişkili bir örnek vardı.

Seçilen cevap aslında başlıktaki soruya değil, verilen örneğe cevap verir. İlk komut bu cevaptır (gerçekten mi? Şüphe ediyorum) ve '/' olmadan da yapabilirdi. İkinci komutun ne yaptığını göremiyorum.

Çeşitli konular karışık:

  • göreceli bir yol adını mutlak bir adla değiştirmek, ne anlama geliyorsa, muhtemelen hiçbir şey. ( Genellikle, böyle bir komut verirseniz touch foo/bar, yol adının foo/barsizin için var olması ve muhtemelen dosya oluşturulmadan önce hesaplamada kullanılması gerekir. )

  • özellikle yoldaki sembolik bağlantılar (sembolik bağlantılar) nedeniyle, ancak muhtemelen başka nedenlerle (bir aygıt salt okunur olarak iki kez bağlanabilir) nedeniyle aynı dosyayı (veya potansiyel dosyayı) gösteren birkaç mutlak yol adı olabilir. Bu gibi sembolikliklerin çözümlenmesi istenebilir veya edilmeyebilir.

  • sembolik olmayan bir dosya veya isme sembolik bağlar zincirinin sonuna ulaşmak. Bu, nasıl yapıldığına bağlı olarak mutlak bir yol adı verebilir veya vermeyebilir. Ve kişi bunu mutlak bir yol adına dönüştürmek isteyebilir veya istemeyebilir.

readlink fooSeçenek içermeyen komut , yalnızca bağımsız değişkeni foosembolik bir bağlantıysa ve bu yanıt bu sembolik bağlantının değeri ise bir yanıt verir . Başka hiçbir bağlantı izlenmez. Cevap göreceli bir yol olabilir: symlink argümanının değeri neydi?

Bununla birlikte, readlinktüm dosyalar için çalışacak ve argüman tarafından belirtilen dosyaya bir mutlak yol adı (sembolik olmayan) verecek seçenekler (-f -e veya -m) vardır.

Bu, bir sembolik olmayan herhangi bir şey için iyi çalışır, ancak yoldaki ara simgeleri çözmeden mutlak bir yol adı kullanmak isteyebilir. Bu komut tarafından yapılırrealpath -s foo

Bir symlink argümanı durumunda readlink, seçenekleri ile argümanın mutlak yolundaki tüm semboller tekrar çözülür, ancak bu, argüman değerini izleyerek karşılaşılabilecek tüm sembolik bağlantıları da içerir. Symlink argümanının kendisine giden mutlak bir yol istiyorsanız, link verebileceklerinden ziyade bunu istemeyebilirsiniz. Yine, foobir symlink ise , realpath -s fooargüman olarak verilenler de dahil olmak üzere, sembolik bağlantıları çözmeden mutlak bir yol alacaktır.

-sSeçenek olmadan, sadece bir bağlantının değerini ve diğer bazı şeyleri okumak dışında realpathhemen hemen aynı readlinkşeyi yapar. readlinkGörünüşe göre, istenmeyen bir artıklık yaratan seçeneklerinin neden olduğu açık değilrealpath .

Web'i keşfetmek çok daha fazla şey söylemez, ancak sistemler arasında bazı farklılıklar olabilir.

Sonuç: realpathen azından burada istenen kullanım için en esnek ve en esnek komut kullanmaktır.


10

Benim favori çözümdü biri diğer araçlardan varlığını (coreutils paketi) anlamına gelmediğini çünkü @EugenKonkov tarafından.

Ancak göreli yollar "" için başarısız oldu. ve "..", işte bu özel durumları ele alan biraz geliştirilmiş bir versiyon.

Yine de, kullanıcı cdgöreli yolun üst dizinine girme iznine sahip değilse başarısız olur .

#! /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'in cevabı benim için pek işe yaramadı ama bu işe yaradı:

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

Yan not, geçerli çalışma dizininiz etkilenmez.


Uyarı: bu komut dosyasıdır. burada 1 dolar ilk argüman
Eugen Konkov

5

En iyi çözüm, imho, burada yayınlanan çözümdür: https://stackoverflow.com/a/3373298/9724628 .

Çalışması için python gerektiriyor, ancak kenar kasalarının tümünü veya çoğunu kapsıyor ve çok taşınabilir bir çözüm gibi görünüyor.

  1. Çözüm simgelerini çözerek:
python -c "import os,sys; print(os.path.realpath(sys.argv[1]))" path/to/file
  1. veya onsuz:
python -c "import os,sys; print(os.path.abspath(sys.argv[1]))" path/to/file

3

Böyle bir durumda, findarama yapmak için mutlak yol vermek muhtemelen en kolay yoldur, örneğin:

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

3

Gerçek yol bulunmayan veya okuma bağlantısı mutlak yolu yazamayan Mac OS X'te bash kullanıyorsanız , yazdırmak için kendi sürümünüzü kodlamaktan başka seçeneğiniz olabilir. İşte benim uygulama:

(saf 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[*]}"
)
}

(gawk kullanın)

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
}

(saf 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)
}

misal:

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

1

Söyledikleri, find $PWDveya dışında (bash) find ~+biraz daha uygun.


1

@ Ernest-a'nın cevabına benzer, ancak $OLDPWDyeni bir işlevi etkilemeden veya tanımlamaksızın bir alt kabuğu ateşleyebilirsiniz(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
Kısa süreli sınırlı yardım sağlayabilecek bu kod snippet'i için teşekkür ederiz. Uygun bir açıklama , bunun neden problem için iyi bir çözüm olduğunu göstererek uzun vadeli değerini büyük ölçüde artıracak ve diğer benzer sorularla gelecekteki okuyucular için daha yararlı hale getirecektir. Yaptığınız varsayımlar dahil bazı açıklamalar eklemek için lütfen yanıtınızı düzenleyin .
Toby Speight

1

@ Ernest-a'nın oldukça güzel versiyonunda bir gelişme:

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

Bu, yolun son öğesinin olduğu durumla doğru bir şekilde ilgilenir .., bu durumda "$(pwd)/$(basename "$1")"in @ ernest-a'nın cevabı olarak gelir accurate_sub_path/spurious_subdirectory/...


0

Göreli yol içeren bir değişkeni mutlak olana dönüştürmek istiyorsanız, bu işe yarar:

   dir=`cd "$dir"`

"cd" çalışma dizinini değiştirmeden yankılanır, çünkü burada bir alt kabukta yürütülür.


2
Bash-4.3-p46'da bu işe yaramıyor: Ben koştuğumda kabuk boş bir çizgi yazdırıyordir=`cd ".."` && echo $dir
Michael

0

Bu, realpathyüklü olmadığı veya hata koduyla çıktığı için başarısız olduğunda, diğerlerinden zincirlenmiş bir çözümdür , o zaman bir sonraki çözüm yolu doğru alana kadar denenir.

#!/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

Herhangi bir göreli yol $ satırı için bash dizesi yerine kullanabilirsiniz:

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

Temel dize ön ikamesi , burada iyi tartışılan
$ {string / # substring / replacement} formülünü izler
: https://www.tldp.org/LDP/abs/html/string-manipulation.html

\Karakter olumsuzlar /biz biz / bulmak yerine İpin parçası olmak istediğinizde.


0

Mac OS Catalina, Ubuntu 16 ve Centos 7 arasında düzgün taşınabilir bir çözüm bulamadım, bu yüzden python inline ile yapmaya karar verdim ve bash scriptlerim için iyi çalıştı.

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

to_abs_path "/some_path/../secrets"
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.