Risposte:
Dato un percorso canonico, come il tuo, funzionerà:
set -f --; IFS=/
for p in $pathname
do [ -e "$*/$p" ] || break
set -- "$@" "$p"
done; printf %s\\n "$*"
Che stampa attraverso l'ultimo componente completamente esistente / accessibile di $pathname
e mette ciascuno di questi separatamente nell'array arg. Il primo componente inesistente non viene stampato, ma viene salvato in $p
.
Potresti affrontarlo in modo opposto:
until cd -- "$path" && cd -
do case $path in
(*[!/]/*)
path="${path%/*}"
;; (*) ! break
esac
done 2>/dev/null && cd -
Che tornerà in modo appropriato o ridurrà $path
se necessario. Rifiuta di tentare una modifica /
, ma in caso di successo stamperà sia la directory di lavoro corrente sia la directory in cui passa a stdout. $PWD
Verrà inserita anche la tua corrente $OLDPWD
.
for p in $pathname
sarà soggetto a "suddivisione delle parole" e "espansione del percorso".
$IFS
. funziona esattamente così. non è soggetto all'espansione del nome percorso, tranne per il fatto che la variabile qui chiamata $pathname
viene espansa in una matrice di componenti percorso come suddivisa $IFS
.
$pathname
usando set -f
"che non viene riportato al suo valore predefinito.
Una delle mie utility preferite è namei
, parte di util-linux
e quindi generalmente presente solo su Linux:
$ namei /usr/share/foo/bar
f: /usr/share/foo/bar
d /
d usr
d share
foo - No such file or directory
Ma il suo output non è molto analizzabile. Quindi, se desideri solo sottolineare che manca qualcosa, namei
potrebbe essere utile.
È utile per la risoluzione dei problemi generali di accesso a un percorso, poiché è possibile indurlo a indicare se un componente è un collegamento o un punto di montaggio, nonché le relative autorizzazioni:
$ 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
La capitale D
indica un punto di montaggio.
namei
funziona per me fintanto che lo alimenta un percorso che esiste, ma quando lo do uno che non lo capisco namei: failed to stat: /usr/share/foo/bar: No such file or directory
.
Qualcosa del genere (tenendo conto dei nomi dei percorsi con spazi vuoti incorporati):
#!/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
cd not_a_directory
tua shell scriverà a stderr qualcosa del genere cd:cd:6: no such file or directory: not_a_directory
. In realtà, la shell dell'utente lo farà in un formato con cui probabilmente l'utente ha già molta familiarità. È quasi sempre più facile e migliore alla fine, comunque, fare semplicemente cose e lasciare che la shell gestisca i rapporti, se necessario. Questo tipo di filosofia richiede tuttavia un'attenzione molto rigorosa per restituire valori e la promozione / conservazione degli stessi.
Solo una soluzione alternativa per bash, supponendo che il percorso sia un percorso assoluto (inizia con /):
#!/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"
pa
come pa_prev
prima riga del ciclo while (prima che venga incrementato). Quando il test per "pa" fallisce, pa_prev
ha l'ultima directory esistente nel percorso indicato.
(( 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
non è semplice ma puoi inserirlo in uno script, renderlo eseguibile e incollarlo da qualche parte nel tuo percorso, se lo utilizzerai frequentemente.
Avvertenza: se il nome della directory a qualsiasi livello contiene un space
carattere, NON funzionerà.
access(2)
non è molto granulare, quindi la soluzione prevede in genere di scrivere qualcosa per iterare e testare ogni elemento del percorso a sua volta ...