回答:
あなたのような正規のパス名が与えられた場合、これは動作します:
set -f --; IFS=/
for p in $pathname
do [ -e "$*/$p" ] || break
set -- "$@" "$p"
done; printf %s\\n "$*"
これは、の最後の完全に存在する/アクセス可能なコンポーネントを通して出力し、$pathname
それらのそれぞれをarg配列に個別に入れます。最初に存在しないコンポーネントは印刷されませんが、で保存され$p
ます。
逆にアプローチするかもしれません:
until cd -- "$path" && cd -
do case $path in
(*[!/]/*)
path="${path%/*}"
;; (*) ! break
esac
done 2>/dev/null && cd -
それは適切に戻るか$path
、必要に応じて削減されます。への変更を試みることを拒否し/
ますが、成功すると、現在の作業ディレクトリとstdoutに変更するディレクトリの両方を印刷します。あなたの電流も同様に$PWD
入れ$OLDPWD
られます。
$IFS
ます。それがまさにその仕組みです。ここで呼び出される変数$pathname
は、分割されたパスコンポーネントの配列に展開されることを除いて、パス名展開の対象ではありません$IFS
。
私のお気に入りのユーティリティの1つはnamei
、の一部でutil-linux
あり、したがって一般的にLinuxにのみ存在します。
$ namei /usr/share/foo/bar
f: /usr/share/foo/bar
d /
d usr
d share
foo - No such file or directory
しかし、その出力はあまり解析できません。そのため、何か不足していることを指摘したいだけであれば、namei
役に立つかもしれません。
パスにアクセスする際の一般的な問題のトラブルシューティングに役立ちます。これは、コンポーネントがリンクかマウントポイントか、およびそのアクセス許可を示すことができるためです。
$ 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
大文字D
はマウントポイントを示します。
namei
フィードが存在するパスである限りは機能しますが、パスを渡さないと取得できませんnamei: failed to stat: /usr/share/foo/bar: No such file or directory
。
次のようなもの(空白が埋め込まれたパス名の計算):
#!/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
、あなたのシェルは同じようstderrの何かに書き込みますcd:cd:6: no such file or directory: not_a_directory
。実際、ユーザーのシェルは、ユーザーが既に非常によく知っている形式でそうします。とにかく、ほとんどの場合、とにかく物事を行い、必要に応じてシェルがレポートを処理できるようにすることで、最終的にはより簡単で優れたものになります。ただし、この種の哲学では、値を返し、その値を昇格/保存するために非常に厳密な注意が必要です。
パスが絶対パス(/で始まる)であると仮定した場合のbashの代替ソリューションにすぎません:
#!/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
しpa_prev
ました。「pa」のテストが失敗pa_prev
すると、指定されたパスに最後に存在するディレクトリがあります。
(( 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
単純ではありませんが、頻繁に使用する場合は、スクリプトに入れて実行可能にし、パスのどこかに貼り付けることができます。
注意事項:任意のレベルのディレクトリ名にspace
文字が含まれている場合、これは機能しません。
access(2)
細かくはないので、ソリューションは通常、各パス要素を順番に繰り返しテストするために何かを書くことを伴います