मैं एक लंबे रास्ते में पहली लापता निर्देशिका कैसे पा सकता हूं?


14

कल्पना कीजिए कि मेरे पास एक रास्ता है जो मौजूद नहीं है:

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

लेकिन चलो कहते हैं /foo/bar कि मौजूद है। क्या मेरे लिए यह निर्धारित करने का एक त्वरित तरीका है कि bazमार्ग में ब्रेकिंग पॉइंट है?

मैं बैश का उपयोग कर रहा हूं।


access(2)बहुत दानेदार नहीं है, इसलिए समाधान में आमतौर पर प्रत्येक पथ तत्व को पुनरावृति और परीक्षण करने के लिए कुछ लिखना शामिल है ...
23

जवाबों:


5

आपके जैसे एक विहित पथनामे को देखते हुए, यह काम करेगा:

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

कि अंतिम पूरी तरह से मौजूदा / सुलभ घटक के माध्यम से प्रिंट करता है $pathname, और उन में से प्रत्येक को अलग से आर्ग सरणी में डालता है। पहले कोई नहीं घटक मुद्रित नहीं है, लेकिन यह में सहेजा गया है $p

आप इसका विरोध कर सकते हैं:

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

जो या तो उचित $pathरूप से वापस आ जाएगा या आवश्यकतानुसार नीचे गिर जाएगा । यह करने के लिए एक परिवर्तन का प्रयास करने के लिए गिरावट आती है /, लेकिन अगर सफल अपने वर्तमान काम कर रहे निर्देशिका और निर्देशिका के लिए दोनों को मुद्रित करेगा, जो इसे बदल जाता है। आपका करंट $PWDभी लगा दिया जाएगा $OLDPWD


स्पष्ट रूप से: for p in $pathname"शब्द विभाजन" और "पथनाम विस्तार" के अधीन होगा।

1
@BinaryZebra - हाँ, यह विभाजित है $IFS। ठीक इसी तरह से यह काम करता है। यह पथनाम विस्तार के अधीन नहीं है, सिवाय इसके कि यहां चर $pathnameको पथ घटकों के एक सरणी में विभाजित होने के रूप में विस्तारित किया गया है $IFS
mikeserv

आप "पथनाम विस्तार" को var पर $pathname प्रयोग करके टाल रहे हैं set -f"जो अपने डिफ़ॉल्ट मान पर वापस नहीं आता है।

@ BinaryZebra - im किसी भी चीज़ से परहेज नहीं करता। im पर्यावरण को मजबूत बनाने के लिए मुझे इसकी आवश्यकता है। बस इतना ही। नहीं - यह अपने डिफ़ॉल्ट मूल्य पर नहीं लौटा है और न ही यह पूछने वाले के कंप्यूटर पर खुद को स्थापित करेगा या मुझे नाश्ता करवाएगा।
15

1
@BinaryZebra - अगर, किसी भी अच्छे प्रोग्रामर को चाहिए, तो आप अक्सर अपने आप को अनावश्यक रूप से अपने निष्पादन के माहौल को प्रभावित / ठीक करने के बारे में चिंता करते हुए पाते हैं, आप इसमें रुचि ले सकते हैं ns, जो कि अगर यहाँ उपयोग किया जाता है, तो यह चर्चा म्यूट प्रस्तुत करेगा।
mikeserv

12

मेरी पसंदीदा उपयोगिताओं में से एक namei, का हिस्सा है util-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
कुजूरू

@kuzzooroo नामी का कौन सा संस्करण?
मुरु

नामी का मेरा संस्करण न तो इसकी मदद में कोई संस्करण देता है और न ही इसके मैन पेज पर और न ही झंडे की सूचना देने वाले संस्करण का समर्थन करता है। मैं यह निर्धारित करने में सक्षम हूं कि यह पैकेज linux-utils 2.16-1ubuntu5 से आता है, लेकिन यह पता नहीं लगा सकता है कि namei के संस्करण के लिए इसका क्या अर्थ है।
कुजूरू

@kuzzooroo चूंकि Ubuntu 12.04 में भी 2.20.1 है , इसलिए आपको Ubuntu के बहुत पुराने संस्करण पर होना चाहिए। 10.04?
मूरू

1

कुछ इस तरह से (एम्बेडेड रिक्त स्थान वाले पथनामों का लेखा):

#!/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
यदि आप सिर्फ cd not_a_directoryअपने खोल बस कुछ लिखने की तरह लिखेंगे cd:cd:6: no such file or directory: not_a_directory। दरअसल, उपयोगकर्ता का शेल एक प्रारूप में ऐसा करेगा जिसके साथ उपयोगकर्ता शायद पहले से ही बहुत परिचित है। इसके लगभग हमेशा सिर्फ दोनों आसान है और वैसे भी अंत में बेहतर करने के लिए कर सामान और खोल संभाल आवश्यक के रूप में रिपोर्टिंग करते हैं। इस तरह के दर्शन को मूल्यों को लौटाने और उसी के प्रचार / संरक्षण पर बहुत सख्त ध्यान देने की आवश्यकता है।
mikeserv

1

बस मार के लिए एक वैकल्पिक समाधान, यह मानते हुए कि मार्ग एक पूर्ण पथ है (/ के साथ शुरू होता है):

#!/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_prevदिए गए पथ में अंतिम मौजूदा निर्देशिका है।
विले

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

यह सरल नहीं है, लेकिन आप इसे एक स्क्रिप्ट में रख सकते हैं, इसे निष्पादन योग्य बना सकते हैं और इसे अपने रास्ते में कहीं भी चिपका सकते हैं, यदि आप इसे अक्सर उपयोग करने जा रहे हैं।

कैविट एम्प्टर: यदि किसी भी स्तर पर आपकी निर्देशिका के नाम में एक spaceवर्ण है, तो यह काम नहीं करेगा।


क्या यह बैश कोड है? मुझे $ {dir} में स्वैप करना पड़ रहा था, इसलिए मैं $ 1 में स्वैप किया, लेकिन अब sdir मेरे लिए खाली आ रहा है।
कुजूरू
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.