Odpowiedzi:
Biorąc pod uwagę kanoniczną nazwę ścieżki, taką jak Twoja, zadziała to:
set -f --; IFS=/
for p in $pathname
do [ -e "$*/$p" ] || break
set -- "$@" "$p"
done; printf %s\\n "$*"
Spowoduje to wydrukowanie ostatniego w pełni istniejącego / dostępnego komponentu $pathname
i umieszczenie każdego z nich osobno w tablicy arg. Pierwszy nieistniejący składnik nie jest drukowany, ale jest zapisywany $p
.
Możesz podejść do tego przeciwnie:
until cd -- "$path" && cd -
do case $path in
(*[!/]/*)
path="${path%/*}"
;; (*) ! break
esac
done 2>/dev/null && cd -
To albo wróci odpowiednio, albo w $path
razie potrzeby zmniejszy koszty . Odmawia próby zmiany /
, ale jeśli się powiedzie, wydrukuje zarówno bieżący katalog roboczy, jak i katalog, w którym zmienia się na standardowe wyjście. Twój prąd również $PWD
zostanie włączony $OLDPWD
.
$IFS
. dokładnie tak to działa. nie podlega rozszerzaniu nazw ścieżek, z tym wyjątkiem, że zmienna tutaj nazywana $pathname
jest rozwijana do tablicy składników ścieżek w podziale $IFS
.
Jednym z moich ulubionych programów jest namei
część util-linux
i stąd ogólnie obecna tylko w Linuksie:
$ namei /usr/share/foo/bar
f: /usr/share/foo/bar
d /
d usr
d share
foo - No such file or directory
Ale jego wyniki nie są bardzo analizowalne. Więc jeśli chcesz tylko wskazać, że czegoś brakuje, namei
może być przydatne.
Przydaje się to do rozwiązywania ogólnych problemów z dostępem do ścieżki, ponieważ można ustawić, czy komponent jest linkiem czy punktem podłączenia, a także uprawnienia:
$ 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
Stolica D
wskazuje punkt montowania.
namei
działa dla mnie tak długo, jak jest to kanał, który istnieje, ale gdy dam mu taki, którego nie dostanę namei: failed to stat: /usr/share/foo/bar: No such file or directory
.
Coś w tym stylu (uwzględnianie ścieżek z osadzonymi odstępami):
#!/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
twoja powłoka napisze do stderr coś w rodzaju cd:cd:6: no such file or directory: not_a_directory
. W rzeczywistości powłoka użytkownika zrobi to w formacie, z którym użytkownik prawdopodobnie już jest bardzo dobrze zaznajomiony. W końcu prawie zawsze jest to łatwiejsze i lepsze, aby po prostu robić różne rzeczy i pozwolić powłoce obsługiwać raportowanie w razie potrzeby. Tego rodzaju filozofia wymaga jednak bardzo ścisłej uwagi na temat zwracanych wartości oraz ich promowania / zachowania.
Tylko alternatywne rozwiązanie dla bash, zakładając, że ścieżka jest ścieżką absolutną (zaczyna się od /):
#!/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
jako pa_prev
pierwszą linię pętli while (zanim zostanie zwiększona). Gdy test „pa” nie powiedzie się, pa_prev
ma ostatni istniejący katalog w podanej ścieżce.
(( 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
nie jest to proste, ale możesz umieścić go w skrypcie, sprawić, by był wykonywalny i umieścić go gdzieś na swojej ścieżce, jeśli będziesz go często używać.
Zastrzeżenie emptor: Jeśli nazwa katalogu na dowolnym poziomie zawiera space
znak, to NIE zadziała.
access(2)
nie jest zbyt szczegółowe, więc rozwiązanie zazwyczaj polega na napisaniu czegoś do iteracji i przetestowaniu kolejno każdego elementu ścieżki ...