OS X'den rastgele bir dosyanın mutlak yolunu alma


18

Ben bir OS X (Linux altında `` readlink -f '' gibi) bir dosyaya mutlak ve standartlaştırılmış yolu bulmak için Bash içinde kullanılabilecek basit bir komut arıyorum.

Aşağıdaki örnek bash oturumu, istenen davranışı gösteren `` abspath '' adlı [hayali] bir yardımcı programı açıklar:

$ pwd
/Users/guyfleegman

$ ls -lR
drwxr-xr-x  4 guyfleegman  crew  136 Oct 30 02:09 foo

./foo:
-rw-r--r--  1 guyfleegman  crew  0 Oct 30 02:07 bar.txt
lrwxr-xr-x  1 guyfleegman  crew  7 Oct 30 02:09 baz.txt -> bar.txt


$ abspath .
/Users/guyfleegman

$ abspath foo
/Users/guyfleegman/foo

$ abspath ./foo/bar.txt
/Users/guyfleegman/foo/bar.txt

$ abspath foo/baz.txt
/Users/guyfleegman/foo/baz.txt

Yukarıdaki örnekte son `` abspath '' çağrısında olduğu gibi, sembolik bağlantıları otomatik olarak çözmemesini tercih ederim, ama burada çok seçici olmayacağım.


Yanıtlar:


16
function abspath() { pushd . > /dev/null; if [ -d "$1" ]; then cd "$1"; dirs -l +0; else cd "`dirname \"$1\"`"; cur_dir=`dirs -l +0`; if [ "$cur_dir" == "/" ]; then echo "$cur_dir`basename \"$1\"`"; else echo "$cur_dir/`basename \"$1\"`"; fi; fi; popd > /dev/null; }

Örnekler:

abspath / => /

abspath /.DS_Store => /.DS_Store

abspath ~ => /Users/mschrag

cd /tmp; abspath . => /tmp

cd /; abspath .DS_Store => /.DS_Store

11

Bunu yapan bir buildin komutu olduğunu sanmıyorum. Jesse Wilson bunun için bir bash senaryosu yazdı:

#!/bin/bash
cd -P -- "$(dirname -- "$1")" &&
printf '%s\n' "$(pwd -P)/$(basename -- "$1")"

Bununla birlikte, (yazdırma ) ve ( her iki durumda da yazdırma ) /gibi doğrudan aşağıdaki yollar için iyi çalışmaz . Değiştirmeye çalıştım, ama yetersiz bash-fu'm beni başarısızlığa uğrattı./etc//etc.../cwd/.

İşte benim önerim:

#!/usr/bin/env python
import os.path
import sys

for arg in sys.argv[1:]:
    print os.path.abspath(arg)

Farklı kaydedin /usr/bin/abspathveya böyle bir şey ve yürütülebilir yapın. Örnek çıktı:

Servus08:~ danielbeck$ abspath .
/Users/danielbeck
Servus08:~ danielbeck$ abspath /tmp
/tmp
Servus08:~ danielbeck$ abspath Documents
/Users/danielbeck/Documents
Servus08:~ danielbeck$ abspath . /tmp Documents
/Users/danielbeck
/tmp
/Users/danielbeck/Documents

Eğer varsa yapmak Sembolik bağ çözünürlük istiyor, değiştirmek printböyle hattı:

    print os.path.realpath(os.path.abspath(arg))

bunu elde etmek için:

Servus08:~ danielbeck$ abspath . /tmp Documents
/Users/danielbeck
/private/tmp
/Users/danielbeck/Documents

1
İlk kabuk temelli yaklaşımla doğru yolda olduğunuzu düşünüyorum, ancak bunu yapmak için başka bir dil kullanmanın amacı biraz bozduğuna inanıyorum, çünkü ek bağımlılıklar getiriyor ve GNU'nun `` readlink '' sürümünü derlemeye hemen hemen eşdeğer (1) 'OS X altında (bunun yapılabileceğini varsayarsak; henüz doğrulamamıştım).
Michael Wehner

2
@Michael GNU readlink'i olan bir sistemde mi yoksa OS X'te mi? OS X'te Python kutudan çıkar çıkmaz çıkar. Teoride bu pratikte yeni bir bağımlılık değil. Her neyse, size sunabileceğim tek şey bu.
Daniel Beck

Eğer aşırı basitse, ima ettiğiniz pragmatik yaklaşım övgüye değerdir. Her halükarda, bu yaklaşımı tamamen bash'da yazılan herhangi bir şey yerine (eğer kesinlikle yapılabilir ve başka bir şeye bağlı değildir - sadece bir satırda kolayca yapılamaz) yerine koyarsak, Python muhtemelen en iyi seçim değil. Hem Perl hem de Ruby (ve muhtemelen PHP) gerçek bir komut dosyası oluşturmaya gerek kalmadan bunu komut satırında kısa bir süre için yapabilir.
Michael Wehner

1
@Michael: Doğru, ama yorumda bulunmadığım şey bu değildi. Size Jesse Wilson tarafından saf bash ile yazılmış% 90'lık bir çözüm öneriyorum + analizinin neden sadece% 90 olduğunu. Bu senin için sorun değilse, sorun değil. Ayrıca size Python'da biraz daha karmaşık,% 100 bir çözüm verdim. Diğer komut dosyası dilleri daha kısa olsa da (Perl rezil olarak :-)), hepsi komutun saklanması için ek bir dosya gerektirir. Yoksa her kullanmak istediğinizde yazmak mı istiyorsunuz? Bu nedenle, birden fazla parametreyi işlemek için çok satırlı yeteneği de ekledim, 1 veya 2 satır sonra farklı yapmaz.
Daniel Beck

2
@Michael, Python neden OS X için iyi bir seçim olmasın? Hatta aslında Python komut dosyaları olan komutlarla birlikte gelirfile /usr/bin/xattr
Arjan

8

Bir seçenek sadece coreutils kurmak ve kullanmak olacaktır greadlink -f. Simgelerini çözer ve eğer varsa /Foo/ya da ~/foo.txtyoksa çalışırlar, /Foo/foo.txteğer /Foo/yoksa değil ile çalışırlar .

$ brew install coreutils
$ greadlink -f /etc
/private/etc
$ greadlink -f ~/Documents/
/Users/lauri/Documents
$ greadlink -f ..
/Users
$ greadlink -f //etc/..////
/private
$ greadlink -f /Foo
/Foo
$ greadlink -f /Foo/foo.txt
$ 

Bu sembolik bağlantıları çözmez ve ikisiyle de çalışmaz /Foo/foo.txt.

abspath() {
  if [ -d "$1" ]; then
    ( cd "$1"; dirs -l +0 )
  else
    ( cd "$(dirname "$1")"; d=$(dirs -l +0); echo "${d%/}/${1##*/}" )
  fi
}

abspath /etc # /etc
abspath ~/Foo/foo.txt # doesn't work
abspath ~/Foo # works
abspath .
abspath ./
abspath ../
abspath ..
abspath /
abspath ~
abspath ~/
abspath ~/Documents
abspath /\"\ \'
abspath /etc/../etc/
abspath /private//etc/
abspath /private//
abspath //private # //private
abspath ./aa.txt
abspath aa.tar.gz
abspath .aa.txt
abspath /.DS_Store
abspath ~/Documents/Books/

dirs -ltilde genişletme gerçekleştirir. dirs +0yığında başka dizinler varsa yalnızca en üstteki dizini yazdırır.


2

Sanırım bunu piton ya da yakutla yapabilirsin.

$ ruby -e 'puts File.expand_path("~/somepath")'

veya komutunu

#!/usr/bin/env ruby
puts File.expand_path(ARGV[0])

Daniel Beck'in cevabı hakkındaki önceki yorumum burada da geçerlidir (tamamen Bash-y çözümünü tercih ederim), ancak bunu başarmak için başka bir dil kullanmaya başvurursam, kısacası için çözümünüzü en iyi şekilde seviyorum. :) Ayrıca yakut çağrısını da sararım (örn. İşlev abspath () {ruby -e "File.expand_path ('$ 1')";}) ve `` .profile'ım '' içine koyar.
Michael Wehner

1

Perl için File :: Spec modülünü kurduysanız, bunu yapabilirsiniz:

perl -MFile::Spec -e 'print File::Spec->rel2abs("../however/complex/../you/want/to.get"), "\n"'

0

Bash / sh komut dosyaları için bu yinelenen işlevi kullanabilirsiniz:

canonical_readlink ()
{
    cd `dirname $1`;
    __filename=`basename $1`;
    if [ -h "$__filename" ]; then
        canonical_readlink `readlink $__filename`;
    else
        echo "`pwd -P`";
    fi
}

answer=$(canonical_readlink $0)

Bazı değişkenler ve komut ikameleri düzgün şekilde alıntılanmamıştır. Gibi değişken adları yerine yerel değişkenler kullanabilirsiniz __filename. Komut dosyası şu anda dirnamezaten daha çok çalışıyor .
Lri

0

OSX için aşağıdaki kitaplığı yükleyin:

brew install coreutils

greadlink -f file.txt

0

Coreutils kurmak bir seçenek değilse, aşağıdaki sembolik kombinasyonları ele alır. ve .. ve GNU realpath gibi dosya ve klasörler üzerinde çalışır:

#!/usr/bin/env bash
realpath()
{
    if ! pushd $1 &> /dev/null; then 
        pushd ${1##*/} &> /dev/null
        echo $( pwd -P )/${1%/*}
    else
        pwd -P
    fi
    popd > /dev/null
}

Ancak realpath'in - ilgili - özelliğini desteklemez. Bunun için /programming//a/12498485/869951 gerekir .


0

Kısıtlamanın MacOS (o sırada OS X) olduğu göz önüne alındığında, varsayılan olarak PHP kullanılabilir. Bu, dosyanın kök dizinini döndürür. dirnameDosyayı almak için de kaldırın .

export SOURCE_DIRECTORY="$(php -r 'echo dirname(realpath($argv[1]));' -- "${BASH_SOURCE[0]}")"
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.