bash - भीतर से एक बैश स्क्रिप्ट की स्रोत निर्देशिका प्राप्त करना
directory (20)
मैं उस स्क्रिप्ट के अंदर , उस निर्देशिका का पथ कैसे प्राप्त करूं जिसमें Bash स्क्रिप्ट स्थित है?
उदाहरण के लिए, मान लीजिए कि मैं एक बैश स्क्रिप्ट का उपयोग किसी अन्य एप्लिकेशन के लिए लॉन्चर के रूप में करना चाहता हूं। मैं कार्यशील निर्देशिका को उस स्थान पर बदलना चाहता हूं जहां बैश स्क्रिप्ट स्थित है, इसलिए मैं उस निर्देशिका में फ़ाइलों पर काम कर सकता हूं, जैसे:
$ ./application
Dirname कमांड सबसे बुनियादी है, बस $ 0 (स्क्रिप्ट नाम) चर के फ़ाइल नाम से पथ को पार्स करना:
dirname "$0"
लेकिन, जैसे मैट बी ने बताया, स्क्रिप्ट को कॉल करने के तरीके के आधार पर लौटाया गया पथ अलग है। pwd नौकरी नहीं करता है क्योंकि यह केवल आपको बताता है कि वर्तमान निर्देशिका क्या है, न कि स्क्रिप्ट किस निर्देशिका में रहती है। इसके अतिरिक्त, यदि किसी स्क्रिप्ट के लिए प्रतीकात्मक लिंक निष्पादित किया गया है, तो आपको एक (शायद सापेक्ष) पथ प्राप्त होगा जहां लिंक रहता है, वास्तविक स्क्रिप्ट नहीं।
कुछ अन्य ने रीडलिंक कमांड का उल्लेख किया है, लेकिन इसके सबसे सरल पर, आप इसका उपयोग कर सकते हैं:
dirname "$(readlink -f "$0")"
रीडलिंक फाइल सिस्टम की जड़ से एक पूर्ण पथ के लिए स्क्रिप्ट पथ को हल करेगा। इसलिए, एकल या डबल डॉट्स, टिल्ड और / या प्रतीकात्मक लिंक वाले किसी भी पथ को पूर्ण पथ में हल किया जाएगा।
इनमें से प्रत्येक को प्रदर्शित करने वाली एक स्क्रिप्ट यहां दी गई है, whatdir.sh:
#!/bin/bash
echo "pwd: `pwd`"
echo "\$0: $0"
echo "basename: `basename $0`"
echo "dirname: `dirname $0`"
echo "dirname/readlink: $(dirname $(readlink -f $0))"
एक सापेक्ष पथ का उपयोग करके, मेरे घर डीआईआर में इस स्क्रिप्ट को चला रहा है:
>>>$ ./whatdir.sh
pwd: /Users/phatblat
$0: ./whatdir.sh
basename: whatdir.sh
dirname: .
dirname/readlink: /Users/phatblat
फिर से, लेकिन स्क्रिप्ट के लिए पूर्ण पथ का उपयोग कर:
>>>$ /Users/phatblat/whatdir.sh
pwd: /Users/phatblat
$0: /Users/phatblat/whatdir.sh
basename: whatdir.sh
dirname: /Users/phatblat
dirname/readlink: /Users/phatblat
अब निर्देशिका बदल रहा है:
>>>$ cd /tmp
>>>$ ~/whatdir.sh
pwd: /tmp
$0: /Users/phatblat/whatdir.sh
basename: whatdir.sh
dirname: /Users/phatblat
dirname/readlink: /Users/phatblat
और अंत में स्क्रिप्ट निष्पादित करने के लिए एक प्रतीकात्मक लिंक का उपयोग करना:
>>>$ ln -s ~/whatdir.sh whatdirlink.sh
>>>$ ./whatdirlink.sh
pwd: /tmp
$0: ./whatdirlink.sh
basename: whatdirlink.sh
dirname: .
dirname/readlink: /Users/phatblat
आप $ BASH_SOURCE का उपयोग कर सकते हैं
#!/bin/bash
scriptdir=`dirname "$BASH_SOURCE"`
ध्यान दें कि आपको #! / Bin / bash का उपयोग करने की आवश्यकता है और # b / bin / sh नहीं है क्योंकि यह एक बैश एक्सटेंशन है
मैं इस तरह कुछ उपयोग करता हूँ:
# retrieve the full pathname of the called script
scriptPath=$(which $0)
# check whether the path is a link or not
if [ -L $scriptPath ]; then
# it is a link then retrieve the target path and get the directory name
sourceDir=$(dirname $(readlink -f $scriptPath))
else
# otherwise just get the directory name of the script path
sourceDir=$(dirname $scriptPath)
fi
मैंने इनमें से हर एक की कोशिश की और उनमें से कोई भी काम नहीं किया। एक बहुत करीब था लेकिन एक छोटी सी बग थी जिसने इसे बुरी तरह तोड़ दिया; वे उद्धरण चिह्नों में पथ लपेटना भूल गए।
इसके अलावा बहुत से लोग मानते हैं कि आप एक शेल से स्क्रिप्ट चला रहे हैं, इसलिए भूलें कि जब आप एक नई स्क्रिप्ट खोलते हैं तो यह आपके घर पर डिफ़ॉल्ट होता है।
आकार के लिए इस निर्देशिका को आजमाएं:
/ var / कोई नहीं / विचार / किसी निर्देशिका / नाम / में होने वाली जगहों के बारे में / और यहां आपकी file.text है
यह इस बात पर ध्यान देता है कि आप इसे कैसे या कहां चलाते हैं।
#!/bin/bash
echo "pwd: `pwd`"
echo "\$0: $0"
echo "basename: `basename "$0"`"
echo "dirname: `dirname "$0"`"
तो इसे वास्तव में उपयोगी बनाने के लिए यहां चल रहे स्क्रिप्ट की निर्देशिका में परिवर्तन कैसे करें:
cd "`dirname "$0"`"
उम्मीद है की वो मदद करदे
यह करना चाहिए:
DIR=$(dirname "$(readlink -f "$0")")
पथ में सिम्लिंक और रिक्त स्थान के साथ काम करता है। डायरनाम और रीडलिंक के लिए मैन पेज देखें।
संपादित करें:
टिप्पणी ट्रैक से ऐसा लगता है कि मैक ओएस के साथ काम नहीं करना है। मुझे नहीं पता कि वह क्यों है। कोई सुझाव?
यह मैक ओएस एक्स 10.6.6 पर वर्तमान कार्यशील निर्देशिका प्राप्त करता है:
DIR=$(cd "$(dirname "$0")"; pwd)
यहां एक पॉज़िक्स अनुपालन एक-लाइनर है:
SCRIPT_PATH=`dirname "$0"`; SCRIPT_PATH=`eval "cd \"$SCRIPT_PATH\" && pwd"`
# test
echo $SCRIPT_PATH
यहां सरल, सही तरीका है:
actual_path=$(readlink -f "${BASH_SOURCE[0]}")
script_dir=$(dirname "$actual_path")
स्पष्टीकरण:
${BASH_SOURCE[0]}
- स्क्रिप्ट का पूरा पथ। इसका मूल्य तब भी सही होगा जब स्क्रिप्ट को सोर्स किया जा रहा हो, उदाहरण के लिएsource <(echo 'echo $0')
प्रिंट बैश करता है , जबकि इसे${BASH_SOURCE[0]}
से${BASH_SOURCE[0]}
स्क्रिप्ट का पूरा पथ प्रिंट करेगा। (बेशक, यह मानता है कि आप ठीक है बैश पर निर्भरता ले रहे हैं।)readlink -f
- निर्दिष्ट पथ में किसी भीreadlink -f
पुनरावर्ती हल करता है। यह एक जीएनयू एक्सटेंशन है, और बीएसडी सिस्टम (उदाहरण के लिए) पर उपलब्ध नहीं है। यदि आप मैक चला रहे हैं, तो आप जीएनयूgreadlink -f
स्थापित करने के लिएgreadlink -f
उपयोग कर सकते हैं और इसेgreadlink -f
साथgreadlink -f
कर सकते हैं।और निश्चित रूप से
dirname
पथ की मूल निर्देशिका हो जाता है।
समाधान ई-सैटिस और 3bcdnlklvc04a के लिए थोड़ा सा संशोधन उनके उत्तर में बताया गया
SCRIPT_DIR=''
pushd "$(dirname "$(readlink -f "$BASH_SOURCE")")" > /dev/null && {
SCRIPT_DIR="$PWD"
popd > /dev/null
}
यह अभी भी सूचीबद्ध सभी मामलों में काम करना चाहिए।
संपादित करें: असफल pushd के बाद popd को रोकें, konsolebox के लिए धन्यवाद
dirname "$0"
प्रयोग करें:
#!/bin/bash
echo "The script you are running has basename `basename "$0"`, dirname `dirname "$0"`"
echo "The present working directory is `pwd`"
अकेले pwd
का उपयोग करना काम नहीं करेगा यदि आप उस निर्देशिका से स्क्रिप्ट नहीं चला रहे हैं जिसमें यह निहित है।
[[email protected] ~]$ pwd
/home/matt
[[email protected] ~]$ ./test2.sh
The script you are running has basename test2.sh, dirname .
The present working directory is /home/matt
[[email protected] ~]$ cd /tmp
[[email protected] tmp]$ ~/test2.sh
The script you are running has basename test2.sh, dirname /home/matt
The present working directory is /tmp
इनमें से कोई भी ओएस एक्स में फाइंडर द्वारा लॉन्च की गई बैश स्क्रिप्ट के लिए काम नहीं करता - मैं इसका उपयोग कर समाप्त हुआ:
SCRIPT_LOC="`ps -p $$ | sed /PID/d | sed s:.*/Network/:/Network/: |
sed s:.*/Volumes/:/Volumes/:`"
सुंदर नहीं है, लेकिन यह काम पूरा हो जाता है।
जीएनयू कोर्यूटल्स रीडलिंक वाले सिस्टम के लिए (उदाहरण के लिए लिनक्स):
$(readlink -f "$(dirname "$0")")
स्क्रिप्ट फ़ाइल नाम BASH_SOURCE
होने पर उपयोग करने की आवश्यकता नहीं है $0
।
निम्नलिखित क्रॉस-संगत समाधान का प्रयास करें:
CWD="$(cd -P -- "$(dirname -- "$0")" && pwd -P)"
जैसे realpath
या readlink
आदेश हमेशा उपलब्ध नहीं होते हैं (ऑपरेटिंग सिस्टम के आधार पर) और ${BASH_SOURCE[0]}
केवल बैश खोल में उपलब्ध है।
वैकल्पिक रूप से आप निम्न फ़ंक्शन को बैश में आज़मा सकते हैं:
realpath () {
[[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
}
यह कार्य 1 तर्क लेता है। यदि तर्क पहले से ही पूर्ण पथ है, तो इसे प्रिंट करें, अन्यथा $PWD
परिवर्तनीय + फ़ाइल नाम तर्क ( ./
उपसर्ग के बिना ) मुद्रित करें ।
सम्बंधित:
यह एकमात्र तरीका है जिसे मैंने विश्वसनीय रूप से बताने के लिए पाया है:
SCRIPT_DIR=$(dirname $(cd "$(dirname "$BASH_SOURCE")"; pwd))
यह बैश-3.2 में काम करता है:
path="$( dirname "$( which "$0" )" )"
यहां इसके उपयोग का एक उदाहरण दिया गया है:
मान लें कि आपके पास ~ / bin निर्देशिका है, जो आपके $ PATH में है । आपके पास इस निर्देशिका के अंदर स्क्रिप्ट ए है। यह स्रोत एस स्क्रिप्ट ~ / बिन / lib / बी । आप जानते हैं कि शामिल स्क्रिप्ट मूल (उपनिर्देशिका lib ) के सापेक्ष है, लेकिन यह उपयोगकर्ता की वर्तमान निर्देशिका के सापेक्ष नहीं है।
यह निम्नलिखित (हल ए के अंदर ) द्वारा हल किया जाता है :
source "$( dirname "$( which "$0" )" )/lib/B"
इससे कोई फ़र्क नहीं पड़ता कि उपयोगकर्ता कहां है या वह स्क्रिप्ट कहता है, यह हमेशा काम करेगा।
हम्म, यदि पथ बेसनाम और डायरनाम में बस इसे काटने और पथ पर चलने के लिए मुश्किल नहीं है (क्या होगा यदि माता-पिता ने पैथ निर्यात नहीं किया है!)। हालांकि, खोल को अपनी स्क्रिप्ट के लिए एक खुले हैंडल होना चाहिए, और बैश में हैंडल # 255 है।
SELF=`readlink /proc/$$/fd/255`
मेरे लिये कार्य करता है।
#!/bin/sh
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
PRG=`readlink "$PRG"`
done
scriptdir=`dirname "$PRG"`
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
एक उपयोगी एक-लाइनर है जो आपको स्क्रिप्ट का पूर्ण निर्देशिका नाम देगा चाहे इससे कहां से कहा जा रहा है।
यह तब तक काम करेगा जब तक स्क्रिप्ट खोजने के लिए उपयोग किए जाने वाले पथ का अंतिम घटक सिमलिंक नहीं है (निर्देशिका लिंक ठीक हैं)। यदि आप स्क्रिप्ट के लिए किसी भी लिंक को हल करना चाहते हैं, तो आपको एक बहु-लाइन समाधान की आवश्यकता है:
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null && pwd )"
SOURCE="$(readlink "$SOURCE")"
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null && pwd )"
यह आखिरी व्यक्ति एलियास, source
, bash -c
, सिम्लिंक इत्यादि के किसी भी संयोजन के साथ काम करेगा।
सावधान रहें: यदि आप इस स्निपेट को चलाने से पहले एक अलग निर्देशिका में cd
करते हैं, तो परिणाम गलत हो सकता है! इसके अलावा, $CDPATH
लिए $CDPATH
।
यह समझने के लिए कि यह कैसे काम करता है, इस वर्बोज़ फ़ॉर्म को चलाने का प्रयास करें:
#!/bin/bash
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
TARGET="$(readlink "$SOURCE")"
if [[ $TARGET == /* ]]; then
echo "SOURCE '$SOURCE' is an absolute symlink to '$TARGET'"
SOURCE="$TARGET"
else
DIR="$( dirname "$SOURCE" )"
echo "SOURCE '$SOURCE' is a relative symlink to '$TARGET' (relative to '$DIR')"
SOURCE="$DIR/$TARGET" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
fi
done
echo "SOURCE is '$SOURCE'"
RDIR="$( dirname "$SOURCE" )"
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
if [ "$DIR" != "$RDIR" ]; then
echo "DIR '$RDIR' resolves to '$DIR'"
fi
echo "DIR is '$DIR'"
और यह कुछ प्रिंट करेगा:
SOURCE './scriptdir.sh' is a relative symlink to 'sym2/scriptdir.sh' (relative to '.')
SOURCE is './sym2/scriptdir.sh'
DIR './sym2' resolves to '/home/ubuntu/dotfiles/fo fo/real/real1/real2'
DIR is '/home/ubuntu/dotfiles/fo fo/real/real1/real2'
SCRIPT_DIR=$( cd ${0%/*} && pwd -P )