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

Mı 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.