İlk eksik dizini uzun bir yolda nasıl bulabilirim?


14

Var olmayan bir yolum olduğunu hayal edin:

$ ls /foo/bar/baz/hello/world
ls: cannot access /foo/bar/baz/hello/world: No such file or directory

Ama diyelim diyelim /foo/bar yapar mevcuttur. Yoldaki bazkırılma noktası olduğunu belirlememin hızlı bir yolu var mı ?

Bash kullanıyorum.


access(2)çok ayrıntılı değildir, bu nedenle çözüm genellikle her bir yol öğesini yinelemek ve test etmek için bir şeyler yazmayı içerir ...
thrig

Yanıtlar:


5

Sizinki gibi kanonik bir yol adı verildiğinde, bu işe yarayacaktır:

set -f --; IFS=/
for p in $pathname
do    [ -e "$*/$p" ] || break
      set -- "$@" "$p"
done; printf %s\\n "$*"

Bu, son tam olarak var olan / erişilebilir bileşeni üzerinden yazdırır $pathnameve bunların her birini ayrı ayrı arg dizisine koyar. Var olmayan ilk bileşen yazdırılmaz, ancak kaydedilir $p.

Buna zıt olarak yaklaşabilirsiniz:

until cd -- "$path" && cd -
do    case   $path  in
      (*[!/]/*)
              path="${path%/*}"
;;    (*)   ! break
      esac
done  2>/dev/null   && cd -

Bu, uygun şekilde geri döner veya $pathgerektiğinde azalır . Değişiklik girişiminde bulunmayı reddeder /, ancak başarılı olursa, hem geçerli çalışma dizininizi hem de stdout olarak değiştirildiği dizini yazdırır. Akımınız $PWDda konacaktır $OLDPWD.


Açıkça: for p in $pathname"kelime bölme" ve "Yol adı genişletmesi" ne tabi olacaktır.

1
@BinaryZebra - evet, bölünmüş durumda $IFS. tam olarak böyle çalışır. burada çağrılan değişkenin $pathnamebölünmüş olarak bir yol bileşenleri dizisine genişletilmesi dışında yol adı genişletmesine tabi değildir $IFS.
mikeserv

Varsayılan değerine döndürülmeyen "seçeneğini $pathname kullanarak set -f"

@BinaryZebra - hiçbir şeyden kaçınmıyorum. Bunu sağlam bir şekilde yapabilmek için ihtiyacım olan ortamı belirtiyorum. bu kadar. hayır - onun varsayılan değerine döndürülmedi ve ne asker's computer kendini yüklemek ya da bana kahvaltı yapmak.
mikeserv

1
@BinaryZebra - by, eğer herhangi bir iyi programcının gerektiği gibi, kendinizi yürütme ortamınızı gereksiz yere etkileme / kurtarma konusunda sık sık endişe duyuyorsanız ns, burada kullanıldığında bu tartışmayı tartışacak olan bir ilgi duyabilirsiniz.
mikeserv

12

En sevdiğim araçlardan biri namei, util-linuxgenellikle Linux'ta bulunan ve bu nedenle genellikle mevcut:

$ namei /usr/share/foo/bar
f: /usr/share/foo/bar
 d /
 d usr
 d share
   foo - No such file or directory

Ancak çıktısı çok ayrıştırılabilir değildir. Yani, sadece bir şeyin eksik olduğunu belirtmek istiyorsanız, nameiyararlı olabilir.

Bir bileşene bir bağlantının mı yoksa bir bağlanma noktasının mı olduğunu ve izinlerini belirtebileceğiniz için, bir yola erişimle ilgili genel sorunları gidermek için kullanışlıdır:

$ ln -sf /usr/foo/bar /tmp/
$ namei -lx /tmp/bar
f: /tmp/bar
Drwxr-xr-x root    root    /
Drwxrwxrwt root    root    tmp
lrwxrwxrwx muru    muru    bar -> /usr/foo/bar
Drwxr-xr-x root    root      /
drwxr-xr-x root    root      usr
                             foo - No such file or directory

Büyük Dharf bir bağlama noktasını belirtir.


@ StéphaneChazelas Diğer sistemlerde eşdeğerlerin bulunabileceğini umdum. BSD'ler için bir şey yok mu?
muru

nameibir yem olduğu sürece benim için çalışıyor, var olan bir yol, ama vermediğim bir yol verdiğimde namei: failed to stat: /usr/share/foo/bar: No such file or directory.
kuzzooroo

@kuzzooroo hangi namei sürümü?
muru

benim namei sürümüm yardımında veya kılavuz sayfasında bir sürüm vermez ve sürüm bilgisi veren bir bayrağı desteklemez. Linux-utils 2.16-1ubuntu5 paketinden geldiğini belirleyebilirim, ancak bunun namei sürümü için ne anlama geldiğini anlayamıyorum.
kuzzooroo

@kuzzooroo Ubuntu 12.04 bile 2.20.1'e sahip olduğundan, gerçekten de Ubuntu'nun çok eski bir sürümünde olmalısınız. 10,04?
muru

1

Bunun gibi bir şey (gömülü boşlukları olan yol adlarını hesaba katar):

#!/bin/sh
explain() {
    if [ -d "$1" ]
    then
        printf "\t%s: is a directory\n" "$1"
    elif [ -e "$1" ]
    then
        printf "\t%s: is not a directory\n" "$1"
    else
        printf "\t%s: does not exist\n" "$1"
    fi
}

for item in "$@"
do
    last=
    test="$item"
    printf "testing: '%s'\n" "$item"
    while [ ! -d "$test" ]
    do
        last="$test"
        test=$(dirname "$test")
        [ -z "$test" ] && break
    done
    if [ -n "$last" ]
    then
        explain "$test"
        explain "$last"
    else
        printf "\t%s: ok\n" "$item"
    fi
done

Argümanların dizinler (veya dizinlere semboller) olması gerektiğini varsayar.
Stéphane Chazelas

1
Eğer sadece cd not_a_directorykabuğunuz stderr'a böyle bir şey yazacaktır cd:cd:6: no such file or directory: not_a_directory. Aslında, kullanıcının kabuğu bunu kullanıcının zaten çok tanıdık olduğu bir biçimde yapar. Neredeyse her zaman hem daha kolay hem de daha iyi sonuçta sadece bir şeyler yapmak ve kabuğun raporlamayı gerektiği gibi işlemesine izin vermek. Bu tür bir felsefe, değerlerin geri dönüşüne ve bunların tanıtımına / korunmasına çok sıkı bir dikkat gerektirir.
mikeserv

1

Sadece bash için alternatif bir çözüm, yolun mutlak bir yol olduğunu varsayarsak (/ ile başlar):

#!/bin/bash

pathname="$1"

IFS='/' read -r -a p <<<"${pathname#/}"

pa=""    max="${#p[@]}"    i=0
while (( i<"$max" )); do
      pa="$pa/${p[i++]}"
      if     [[ ! -e $pa ]]; then
             printf 'failed at: \t"%s"\t"%s"\n' "${pa##*/}" "${pa}"
             break
      fi
done

$ ./script "/foo/ba r/baz/hello/world"
failed at:      "hello"        "/foo/ba r/baz/hello"

Bu benim için çalıştı. Ben kurtardı yüzden, yol dizesinde son geçerli bir yol gerekli paolarak pa_prev(o artırılır hale geçmeden) ise döngünün ilk satırı olarak. "Pa" testi başarısız olursa, pa_prevverilen yolda son varolan dizine sahip olur .
Ville

0
(( dirct=$(echo ${dir}|tr "/" " "|wc -w)+1 ))
i=2
while [ ${i} -le ${dirct} ]
do
  sdir=$(echo ${dir}|cut -d/ -f1,${i})
  if [ ! -d ${sdir} ]
  then
    echo "Path is broken at ${sdir}"
  fi
  (( i++ ))
done

bu basit değildir, ancak sık sık kullanacaksanız bir komut dosyasına koyabilir, yürütülebilir hale getirebilir ve yolunuzda bir yere yapıştırabilirsiniz.

Uyarı emptor: Dizin adınız herhangi bir düzeyde bir spacekarakter içeriyorsa , bu ÇALIŞMAZ.


Bu bash kodu mu? Ben $ {dir} takas zorunda boş geliyordu bu yüzden 1 $ takas, ama şimdi sdir benim için boş geliyor.
kuzzooroo
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.