web-dev-qa-db-ja.com

長いパスで最初に欠落しているディレクトリを見つけるにはどうすればよいですか?

存在しないパスがあると想像してください。

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

しかし、/foo/bardoesが存在するとしましょう。 bazがパスのブレークポイントであると判断する簡単な方法はありますか?

私はBashを使用しています。

14
kuzzooroo

Yoursなどの正規のパス名を指定すると、これは機能します。

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に入れられます。

5
mikeserv

私のお気に入りのユーティリティの1つは nameiutil-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は、マウントポイントを示します。

12
muru

パスが絶対パス(/で始まる)であると仮定した場合の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"
1
user79743

このようなもの(空白が埋め込まれたパス名を考慮):

#!/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
1
Thomas Dickey
(( 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文字が含まれている場合、これは機能しません。

0
MelBurslan