Göreceli yolu sembolik bağ olmadan mutlak yola dönüştürme


63

Mutlak (ve kanonikleştirilmiş) yolu sembolik bağlantılar içerebilecek göreceli bir yoldan almak için bir Unix komutu var mı?

Yanıtlar:


79

readlinkYardımcı programı kullanabilirsiniz -f:

-f, --canonicalize

      canonicalize  by  following  every symlink in every component of
      the given name recursively; all  but  the  last  component  must
      exist

Örneğin GNU coreutils ve FreeBSD kullananlar gibi bazı dağıtımlar, realpath(1)temelde yalnızca realpath(3)aynı şeyi yapan ve yapan bir yardımcı programla birlikte gelir .


16
-fAnahtar Mac OS X (en az 10.8.5 itibariyle) üzerinde mevcut değil. -fAnahtar olmadan sadece bir hata kodu verir.
iconoclast

3
Bazı sistemler ne ile gelen readlinkne de realpathSolaris ve özellikle HP-UX, -.
Sildoreth,

Mac sorunu için: brew install coreutils apple.stackexchange.com/a/69332/23040 ve tüm standart Mac CLI araçlarını yeni yüklenen GNU eşdeğerlerine yönlendiren adımı atmak istemiyorsanız, hemen arayın greadlink.
Adrian,

18

Taşınabilir, PWDdeğişken kabuk tarafından geçerli dizinin mutlak bir konumuna ayarlanır. Bu yolun herhangi bir bileşeni sembolik bir bağlantı olabilir.

case $f in
  /*) absolute=$f;;
  *) absolute=$PWD/$f;;
esac

Ortadan kaldırmak .ve ..aynı zamanda dosyayı içeren dizine geçmek ve $PWDorada edinin :

if [ -d "$f" ]; then f=$f/.; fi
absolute=$(cd "$(dirname -- "$f")"; printf %s. "$PWD")
absolute=${absolute%?}
absolute=$absolute/${f##*/}

Sembolik bağları izlemenin taşınabilir bir yolu yoktur. Bir dizine giden bir yolunuz varsa, çoğu sistemde $(cd -- "$dir" && pwd -P 2>/dev/null || pwd)sembolik bağ kullanmayan bir yol sağlar, çünkü sembolik bağları izleyen kabukları uygulama eğilimindedir pwd -P(“fiziksel” için “P”).

Bazı sendikalar bir dosyaya “fiziksel” yol yazdırmak için bir yardımcı program sağlar.

  • Makul bir şekilde yeni Linux sistemleri (GNU coreutils veya BusyBox ile) readlink -f, FreeBSD ≥8.3, NetBSD ≥4.0 ve OpenBSD’leri de 2.2.
  • FreeBSD .34.3 realpath(bazı Linux sistemlerinde de var ve BusyBox'ta).
  • Perl varsa, Cwdmodülü kullanabilirsiniz .

    perl -MCwd -e 'print Cwd::realpath($ARGV[0])' path/to/file

Neden bir şeyi pwd( $(cd -- "$dir" && pwd -P 2>/dev/null | pwd)) içine sokuyorsun ? Stdin'i umursamıyor gibi gözüküyor.
Mateusz Piotrowski

1
@MateuszPiotrowski Typo, yazmak istemiştim||
Gilles

5

pwdihtiyaçlarınız için uygun? Geçerli dizinin mutlak yolunu verir. Ya da belki istediğin şey realpath () .


3

alisterve rss67de bu makalede en istikrarlı uyumlu ve en kolay yolu tanıtmak. Daha önce bundan daha iyi bir yol görmedim.

RELPATH=./../
cd $RELPATH
ABSPATH=`pwd`

Orijinal konumuna geri dönmek istiyorsanız,

ORGPATH=`pwd`
RELPATH=./../
cd $RELPATH
ABSPATH=`pwd`
cd $ORGPATH

veya

RELPATH=./../
cd $RELPATH
ABSPATH=`pwd`
cd -

Keşke bu yardımcı olsaydı. Bu benim için en büyük çözümdü.


12
Bu aslında iyi bir yol değil. Bir dizinden çıkmak ve tekrar içeri girmek güvenilir değildir: geri gelme izniniz olmayabilir veya bu sırada dizin yeniden adlandırılmış olabilir. Bunun yerine, bir kabuktaki dizinleri değiştirin: ABSPATH=$(cd -- "$RELPATH" && pwd). İkame etrafındaki (tırnak boşluğu ve globbing karakterleri içeriyorsa kırılmayacak şekilde) çift tırnak işaretlerini ve --(yolun başlaması durumunda -) not alın. Ayrıca bu yalnızca dizinler için çalışır ve sembolik bağları istenildiği gibi kurallaştırmaz. Daha fazla ayrıntı için cevabımı gör.
Gilles

"> geri dönme iznine sahip olmayabilirsin" Dirteye cd demek istiyorsun ama geri dönemezsin? Lütfen bazı örnek senaryolar verebilir misiniz?
Talespin_Kit

0

Buradaki diğer cevaplar iyiydi ancak ihtiyaçlarım için yetersizdi. Komut dosyalarımda herhangi bir makinede kullanabileceğim bir çözüme ihtiyacım vardı. Benim çözümüm, ihtiyacım olan senaryolardan çağırabildiğim bir kabuk betiği yazmaktı.

#!/bin/sh
if [ $# -eq 0 ] || [ $# -gt 2 ]; then
  printf 'Usage: respath path [working-directory]\n' >&2
  exit 1
fi
cantGoUp=

path=$1
if [ $# -gt 1 ]; then
  cd "$2"
fi
cwd=`pwd -P` #Use -P option to account for directories that are actually symlinks

#Handle non-relative paths, which don't need resolution
if echo "$path" | grep '^/' > /dev/null ; then
  printf '%s\n' "$path"
  exit 0
fi

#Resolve for each occurrence of ".." at the beginning of the given path.
#For performance, don't worry about ".." in the middle of the path.
while true
do
  case "$path" in
    ..*)
      if [ "$cwd" = '/' ]; then
        printf 'Invalid relative path\n' >&2
        exit 1
      fi
      if [ "$path" = '..' ]; then
        path=
      else
        path=`echo "$path" | sed 's;^\.\./;;'`
      fi
      cwd=`dirname $cwd`
      ;;
    *)
      break
      ;;
  esac
done

cwd=`echo "$cwd" | sed 's;/$;;'`
if [ -z "$path" ]; then
  if [ -z "$cwd" ]; then
    cwd='/'
  fi
  printf '%s\n' "$cwd"
else
  printf '%s/%s\n' "$cwd" "$path"
fi

Bu çözüm, taşınabilirlik için Bourne Kabuğu için yazılmıştır. Bunu "respath.sh" adında bir komut dosyasında buldum.

Bu script şu şekilde kullanılabilir:

respath.sh '/path/to/file'

Ya da böyle

respath.sh '/relative/path/here' '/path/to/resolve/relative/to'

Komut, ikinci argümandaki yolu başlangıç ​​noktası olarak kullanarak, ilk argümandaki yolu çözer. Yalnızca ilk argüman sağlanırsa, komut dosyası mevcut çalışma dizininize göre yolu çözer.


Solaris 10'da ve bugünlerde daha önce yalnızca Bourne kabuğu bulacağınızı unutmayın. O Bourne etti SVR2 yana en Bourne kabuğu uygulamaları gibi (1984) kabuk pwdyerleşik ve desteklemez -P(Bourne kabuğu do POSIX kabukları gibi işleme mantıksal $ PWD uygulamak vermedi).
Stéphane Chazelas

Bourne uyumluluğunu düşürürseniz, POSIX $ {var ## pattern} sözdizimini kullanabilir ve bazı değerlerle kırılacak olan yankılardan kaçının.
Stéphane Chazelas

CD'nin (ve pwd) çıkış durumunu kontrol etmeyi unutuyorsunuz. Muhtemelen cd -P --de, 1. argümanın bazılarını içermesi durumunda kullanmalısınız ..
Stéphane Chazelas 22:15

Çekiniz yerine caseolmalı . ..|../*)..*
Stéphane Chazelas

Kayıp tekliflerden biri vardirname $cwd
Stéphane Chazelas

0

Ek olarak, $1(genellikle ${PWD}) için önceden tanımlanmış bir yolunuz varsa , aşağıdakiler işe yarar:

CWD="${1:-${PredefinedAbsolutePath}}"
if [ "${CWD}" != "${PredefinedAbsolutePath}}" ]; then
    case $1 in
        /*) echo "CWD=${CWD}"; ;;
        *) CWD=$(realpath $1); echo "CWD=${CWD}"; ;;
    esac
fi

0

Diğer herkesin yanıtına saygı duyuyorum, aşağıdaki işlevi linux / MAC OSX arasında her yerde bulduğum diğerlerine göre çok daha kolay ve taşınabilir buldum. Birine yardım edebilir.

#!/usr/bin/bash
get_absolute_path(){
    file_path=`pwd $1`
    echo "$file_path/$1"
}
#to assign to a variable
absolute_path=$(get_absolute_path "file.txt")
echo $absolute_path

-1

A değişkeninin bir yol adı sakladığını varsayın (a = "neyse")

1. Potansiyel boşluk içeren yol için:

c=$(grep -o " " <<< $a | wc -l); if (( $c > "0" )); then a=$(sed 's/ /\\ /g' <<< $a); fi

2. Asıl soru için, yani yolu mutlak hale dönüştürmek: readlink , aşağıdaki gibi kullanılabilen sembolik link içeriğini alabilir. (not readlink -fmükemmel olurdu, ama -f FORMATS'ın anlamına gelir , en azından Mac OS X bash'ta kullanılamaz .)

if [[ $(readlink $a) == "" ]]; then a=$(cd $a; pwd); else a=$(cd $(readlink $a); pwd); fi

3. Sadece öğrenilen pwd -Piçinde man pwd: -P "etmektir (bütün sembolik bağlantılar çözüldü) fiziksel Geçerli çalışma dizini görüntüler ve dolayısıyla"

if (( $(grep -o " " <<< $a | wc -l) > "0" )); then a=$(sed 's/ /\\ /g' <<< $a); fi; a=$(cd $a; pwd -P)

de çalışacak.

Sonuç: Her iki gereksiniminizi de karşılamak için 1'i 2 ile birleştirin , ancak boşluk içeren yol adları daha özlü bir şekilde 3 ele alınır .


Sen yanlışsın. Örneğin, yolunuz yukarıdaki çalışmaların çoğunda bir boşluk içeriyorsa.
Anthon,

ya da bazen bir glob char. Ve istendiği gibi sembolik bağları çözmez.
dave_thompson_085

Boşluk içeren yol adlarıyla ilgili "yorum" yanıtımı sildim ve "yanıt" bölümünü buna göre değiştirdim.
vxtal
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.