मैं किसी फ़ाइल को bash में निरपेक्ष निर्देशिका कैसे प्राप्त करूं?


82

मैंने एक बैश स्क्रिप्ट लिखी है जो एक इनपुट फाइल को एक तर्क के रूप में लेती है और इसे पढ़ती है।
इस फ़ाइल में उपयोग की गई अतिरिक्त फ़ाइलों के लिए कुछ पथ (इसके स्थान के सापेक्ष) हैं।

मैं स्क्रिप्ट को इनपुट फ़ाइल वाले फ़ोल्डर में जाना चाहता हूं, ताकि आगे की कमांड निष्पादित हो सके।

तो, मैं इनपुट फ़ाइल से फ़ोल्डर (और सिर्फ फ़ोल्डर) कैसे प्राप्त करूं? (Linux में)


क्या आप इनपुट फ़ाइल के लिए पूर्ण पथ दे रहे हैं या वर्तमान कार्य निर्देशिका के सापेक्ष केवल पथ है?
dhh

dhm: इनपुट सापेक्ष पथ देता है, मुझे पूर्ण पथ ऋण फ़ाइल नाम चाहिए।
BobMcGee

जवाबों:


152

पूर्ण पथ उपयोग प्राप्त करने के लिए:

readlink -f relative/path/to/file

किसी फ़ाइल की निर्देशिका प्राप्त करने के लिए:

dirname relative/path/to/file

आप दोनों को जोड़ भी सकते हैं:

dirname $(readlink -f relative/path/to/file)

अगर readlink -fआपके सिस्टम पर उपलब्ध नहीं है तो आप इस का उपयोग कर सकते * :

function myreadlink() {
  (
  cd "$(dirname $1)"         # or  cd "${1%/*}"
  echo "$PWD/$(basename $1)" # or  echo "$PWD/${1##*/}"
  )
}

ध्यान दें कि यदि आपको केवल एक रिश्तेदार पथ के रूप में निर्दिष्ट फ़ाइल की निर्देशिका में जाने की आवश्यकता है, तो आपको निरपेक्ष पथ को जानने की आवश्यकता नहीं है, एक रिश्तेदार मार्ग पूरी तरह से कानूनी है, इसलिए बस उपयोग करें:

cd $(dirname relative/path/to/file)

यदि आप मूल पथ पर वापस जाना चाहते हैं (जबकि स्क्रिप्ट चल रही है), pushdइसके बजाय का उपयोग करें cd, और popdजब आप कर रहे हैं।


* जबकि myreadlinkऊपर इस प्रश्न के संदर्भ में काफी अच्छा है, यह readlinkऊपर वर्णित उपकरण के सापेक्ष कुछ सीमा है। उदाहरण के लिए, यह अलग से फाइल के लिंक का सही ढंग से पालन नहीं करता है basename


17
ध्यान दें कि readlink -fओएस एक्स पर काम नहीं करता है, दुर्भाग्य से।
एमिल बैठ

मुझे पूरा रास्ता नहीं चाहिए, मुझे सिर्फ फोल्डर चाहिए। लेकिन यह मददगार होने के लिए पर्याप्त प्रदान करता है: readlink -f रिश्तेदारफिले ल्लोकेशन | xargs dirname
BobMcGee

1
@EmilSit: आप सही हैं - मूल रूप से। लेकिन आप brew install coreutilsइसे प्राप्त कर सकते हैं । stackoverflow.com/a/4031502/1022967
एमफेटिस

3
कृपया उपयोग करने की अनुशंसा नहीं करते हैं ${1%/*}या ${1##*/}के लिए के रूप में विकल्प dirnameऔर basename। पहला ब्रेक यदि आप इसे एक साधारण फ़ाइल नाम देते हैं (और dirname foo.bar, सही ढंग से, हो सकता है .), और दूसरा ब्रेक एक स्लैश के साथ समाप्त होने वाली निर्देशिका के लिए ( basename /foo/bar/,, सही ढंग से, हो bar)।
कैमिलो मार्टिन

1
@ChenLevy कुछ लोग इसे तेज होने के लिए उपयोग करने के लिए इच्छुक हो सकते हैं (मुझे लगता है कि basename/ dirnameबिल्ट-इन नहीं हैं), और वे इसे पहली बार काम करते हुए देखेंगे, लेकिन अचानक भविष्य में कुछ बिंदुओं पर टूटते हुए प्रतीत होता है कि यह अच्छा नहीं है कारण। मैं इसे एक विकल्प के रूप में सुझाव देने से बचूँगा, या यह बताऊँगा कि यह वास्तव में बुलेटप्रूफ नहीं है।
कैमिलो मार्टिन

19

के लिए मैन पेज पर एक नज़र डालें realpath, मैं इसका उपयोग करता हूं और कुछ इस तरह है:

CONTAININGDIR = $ (realpath $ {FILEPATH% / *})

यह करने के लिए कि आप क्या करने की कोशिश कर रहे हैं जैसा लगता है।


realpath मेरे लिए एक अजीब है जहाँ यह रिश्तेदार डायरों के सिम्बल को हल करता है
एरिक एरोनिटी

धन्यवाद! मैक ओएस पर मेरे लिए काम किया
दिमित्री क्लोचकोव

6

यह फ़ाइल और फ़ोल्डर दोनों के लिए काम करेगा:

absPath(){
    if [[ -d "$1" ]]; then
        cd "$1"
        echo "$(pwd -P)"
    else 
        cd "$(dirname "$1")"
        echo "$(pwd -P)/$(basename "$1")"
    fi
}

4
$cat abs.sh
#!/bin/bash
echo "$(cd "$(dirname "$1")"; pwd -P)"

कुछ स्पष्टीकरण:

  1. इस लिपि को तर्क के रूप में सापेक्ष मार्ग मिलता है "$1"
  2. फिर हमें उस पथ का dirname भाग मिलता है (आप इस स्क्रिप्ट में dir या फ़ाइल पास कर सकते हैं):dirname "$1"
  3. तो फिर हम cd "$(dirname "$1");इस रिश्तेदार dir में
  4. pwd -Pऔर पूर्ण पथ प्राप्त करें। -Pविकल्प सिमलिंक से बचने जाएगा
  5. अंतिम चरण के रूप में हम echoइसे

फिर अपनी स्क्रिप्ट चलाएँ:

abs.sh your_file.txt

1

GitHub पर हमारे नए बैश लाइब्रेरी उत्पाद वास्तविकपथ-देयता को आज़माएं , जो हमने समुदाय को मुफ्त और बिना लाइसेंस के उपयोग के लिए दिया है। यह साफ, सरल और अच्छी तरह से प्रलेखित है इसलिए इसे सीखना बहुत अच्छा है। तुम कर सकते हो:

get_realpath <absolute|relative|symlink|local file path>

यह समारोह पुस्तकालय का मूल है:

if [[ -f "$1" ]]
then
    # file *must* exist
    if cd "$(echo "${1%/*}")" &>/dev/null
    then
        # file *may* not be local
        # exception is ./file.ext
        # try 'cd .; cd -;' *works!*
        local tmppwd="$PWD"
        cd - &>/dev/null
    else
        # file *must* be local
        local tmppwd="$PWD"
    fi
else
    # file *cannot* exist
    return 1 # failure
fi

# reassemble realpath
echo "$tmppwd"/"${1##*/}"
return 0 # success

}

यह बैश 4+ है, किसी भी निर्भरता की आवश्यकता नहीं है और get_dirname, get_filename, get_stemname और validate_path भी प्रदान करता है।


0

उपरोक्त उत्तर के साथ समस्या "./" जैसे "./my-file.txt" के साथ फाइल इनपुट के साथ आती है।

वर्कअराउंड (कई का):

    myfile="./somefile.txt"
    FOLDER="$(dirname $(readlink -f "${ARG}"))"
    echo ${FOLDER}

-1

मैं लिनक्स पर रीडलिंक -f काम करता रहा है

इसलिए

FULL_PATH=$(readlink -f filename)
DIR=$(dirname $FULL_PATH)

PWD=$(pwd)

cd $DIR

#<do more work>

cd $PWD

5
बैश में अपरकेस चर नामों का उपयोग न करें, यह एक दिन पहले से मौजूद चर के साथ टकराव होगा ... ओह, और यह दिन अब है: क्या आप जानते हैं कि चर PWDपहले से ही बैश में मौजूद है इसका मूल्य वास्तव में वर्तमान निर्देशिका है? और उद्धरणों का भी अधिक उपयोग करें।
गिन्नौरफ_गनीउरफ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.