मूल रूप से मुझे स्क्रिप्ट को शेल स्क्रिप्ट फ़ाइल स्थान से संबंधित पथ के साथ चलाने की आवश्यकता है, मैं वर्तमान निर्देशिका को उसी निर्देशिका में कैसे बदल सकता हूं जहां स्क्रिप्ट फ़ाइल रहती है?
मूल रूप से मुझे स्क्रिप्ट को शेल स्क्रिप्ट फ़ाइल स्थान से संबंधित पथ के साथ चलाने की आवश्यकता है, मैं वर्तमान निर्देशिका को उसी निर्देशिका में कैसे बदल सकता हूं जहां स्क्रिप्ट फ़ाइल रहती है?
जवाबों:
बैश में, आपको इस तरह की आवश्यकता होनी चाहिए:
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
readlink
(नीचे दिए गए उत्तर को देखें)
$BASH_SOURCE
एवज में उपयोग करना अधिक सुरक्षित होता है $0
, क्योंकि $0
इसमें हमेशा स्क्रिप्ट के मार्ग को शामिल नहीं किया जाता है, जैसे कि किसी स्क्रिप्ट को 'सोर्सिंग' करते समय।
$BASH_SOURCE
बैश-विशिष्ट है, प्रश्न सामान्य रूप से शेल स्क्रिप्ट के बारे में है।
CUR_PATH=$(pwd)
या pwd
वर्तमान निर्देशिका (जिसकी स्क्रिप्ट अभिभावक को नहीं होनी चाहिए) लौटाते हैं!
$BASH_SOURCE
, और यह वही देता है जो मुझे चाहिए था। मेरी स्क्रिप्ट को किसी अन्य स्क्रिप्ट से कॉल किया जा रहा है, और सही उपनिर्देशिका (मेरे मामले में ) $0
रिटर्न .
करते समय । $BASH_SOURCE
scripts
मूल पोस्ट में समाधान होता है (प्रतिक्रियाओं को अनदेखा करें, वे कुछ भी उपयोगी नहीं जोड़ते हैं)। दिलचस्प काम readlink
विकल्प के साथ उल्लेखित यूनिक्स कमांड द्वारा किया जाता है -f
। काम करता है जब स्क्रिप्ट एक निरपेक्ष द्वारा और साथ ही एक रिश्तेदार पथ द्वारा कहा जाता है।
बाश, श, क्ष के लिए:
#!/bin/bash
# Absolute path to this script, e.g. /home/user/bin/foo.sh
SCRIPT=$(readlink -f "$0")
# Absolute path this script is in, thus /home/user/bin
SCRIPTPATH=$(dirname "$SCRIPT")
echo $SCRIPTPATH
Tsh के लिए, csh:
#!/bin/tcsh
# Absolute path to this script, e.g. /home/user/bin/foo.csh
set SCRIPT=`readlink -f "$0"`
# Absolute path this script is in, thus /home/user/bin
set SCRIPTPATH=`dirname "$SCRIPT"`
echo $SCRIPTPATH
इसे भी देखें: https://stackoverflow.com/a/246128/59087
readlink
। इसलिए मैंने पुशड / पॉपड (बैश के लिए बिल्ट-इन) का उपयोग करने की सिफारिश की।
-f
करने का विकल्प readlink
। stackoverflow.com/questions/1055671/…
-f
ओएस एक्स पर बिल्कुल भी समर्थित नहीं है (सिंह के रूप में); वहाँ आप या तो -f
अप्रत्यक्ष स्तर के अधिकांश एक स्तर पर हल करने के लिए pushd "$(dirname "$(readlink "$BASH_SOURCE" || echo "$BASH_SOURCE")")"
कर सकते हैं , उदाहरण के लिए , या आप अपनी खुद की पुनरावर्ती सिम्क्लिन-निम्नलिखित स्क्रिप्ट को लिंक की गई पोस्ट में प्रदर्शित कर सकते हैं।
sh /some/other/directory/script.sh)
, इस मामले में .
आपका pwd होगा, न कि/some/other/directory
एक उत्तर पर पहले की टिप्पणी ने इसे कहा, लेकिन अन्य सभी उत्तरों में से याद करना आसान है।
बैश का उपयोग करते समय:
echo this file: "$BASH_SOURCE"
echo this dir: "$(dirname "$BASH_SOURCE")"
dirname "$BASH_SOURCE"
इसके बजाय $ BASH_SOURCE में रिक्त स्थान को संभालने के लिए उपयोग करना चाहिए ।
"$(dirname "${BASH_SOURCE[0]}")"
मान लें कि आप बैश का उपयोग कर रहे हैं
#!/bin/bash
current_dir=$(pwd)
script_dir=$(dirname $0)
echo $current_dir
echo $script_dir
इस स्क्रिप्ट को उस निर्देशिका को प्रिंट करना चाहिए जो आप अंदर हैं, और फिर वह स्क्रिप्ट जिस निर्देशिका में है। उदाहरण के लिए, इसे /
स्क्रिप्ट से कॉल करते समय /home/mez/
, यह आउटपुट करता है
/
/home/mez
याद रखें, जब एक कमांड के आउटपुट से वेरिएबल्स को असाइन किया जाता है, तो कमांड को इन में लपेटें - $(
और )
- या आपको वांछित आउटपुट नहीं मिलेगा।
यदि आप बैश का उपयोग कर रहे हैं ...।
#!/bin/bash
pushd $(dirname "${0}") > /dev/null
basedir=$(pwd -L)
# Use "pwd -P" for the path without links. man bash for more info.
popd > /dev/null
echo "${basedir}"
pushd
/ popd
के साथ cd $(dirname "${0}")
और cd -
यह अन्य गोले पर काम करते हैं, अगर वे एक है बनाने के लिए pwd -L
।
जैसा कि मैकार्को सुझाव देता है:
BASEDIR=$(dirname $0)
echo $BASEDIR
यह तब तक काम करता है जब तक आप स्क्रिप्ट को उसी डायरेक्टरी से निष्पादित नहीं करते हैं जहां स्क्रिप्ट रहती है, जिस स्थिति में आपको '' '' का मान मिलता है।
उस समस्या का उपयोग करने के लिए:
current_dir=$(pwd)
script_dir=$(dirname $0)
if [ $script_dir = '.' ]
then
script_dir="$current_dir"
fi
स्क्रिप्ट निर्देशिका को संदर्भित करने के लिए अब आप अपनी स्क्रिप्ट में चर current_dir का उपयोग कर सकते हैं। हालाँकि यह अभी भी सहानुभूति समस्या हो सकती है।
इस सवाल का सबसे अच्छा जवाब यहां दिया गया था:
बश लिपि के स्रोत निर्देशिका को भीतर से प्राप्त करना
और यह है:
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
वन-लाइनर जो आपको स्क्रिप्ट की पूरी निर्देशिका का नाम देगा, जहां से इसे बुलाया जा रहा है।
यह समझने के लिए कि यह कैसे काम करता है आप निम्नलिखित स्क्रिप्ट निष्पादित कर सकते हैं:
#!/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'"
आइए इसे बनाते हैं POSIX ऑनलाइनर:
a="/$0"; a=${a%/*}; a=${a#/}; a=${a:-.}; BASEDIR=$(cd "$a"; pwd)
बीएसडी वालों सहित कई बॉर्न-संगत गोले पर परीक्षण किया गया।
जहां तक मुझे पता है कि मैं लेखक हूं और मैंने इसे सार्वजनिक डोमेन में डाल दिया है। अधिक जानकारी के लिए देखें: https://www.jasan.tk/posts/2017-05-11-posix_shell_dirname_nplaceplace/
cd: too many arguments
अगर रास्ते में रिक्त स्थान, और रिटर्न $PWD
। (एक स्पष्ट तय है, लेकिन अभी पता चलता है कि वास्तव में कितने किनारे मामले हैं)
BASE_DIR="$(cd "$(dirname "$0")"; pwd)";
echo "BASE_DIR => $BASE_DIR"
यदि आप वास्तविक स्क्रिप्ट डायरेक्टरी प्राप्त करना चाहते हैं (भले ही आप स्क्रिप्ट को सिम्कलिन या सीधे प्रयोग कर रहे हों), कोशिश करें:
BASEDIR=$(dirname $(realpath "$0"))
echo "$BASEDIR"
यह linux और macOS दोनों पर काम करता है। मैं किसी को भी यहाँ के बारे में उल्लेख नहीं देख सकता था realpath
। सुनिश्चित नहीं हैं कि इस दृष्टिकोण में कोई कमियां हैं या नहीं।
macOS पर, आपको coreutils
उपयोग करने के लिए इंस्टॉल करने की आवश्यकता है realpath
। उदाहरण के लिए: brew install coreutils
।
परिचय
यह उत्तर इस थ्रेड (TheMarko द्वारा लिखित) के बहुत ही टूटे-फूटे लेकिन चौंकाने वाले टॉप वोट किए गए उत्तर को सही करता है:
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
क्यों यह "$ 0" का उपयोग नहीं कर रहा है यह काम नहीं करता है?
dirname $ 0 केवल तभी काम करेगा जब उपयोगकर्ता स्क्रिप्ट को बहुत विशिष्ट तरीके से लॉन्च करेगा। मैं कई स्थितियों को खोजने में सक्षम था जहां यह उत्तर विफल हो जाता है और स्क्रिप्ट को क्रैश कर देता है।
सबसे पहले, आइए समझते हैं कि यह उत्तर कैसे काम करता है। वह स्क्रिप्ट डायरेक्टरी कर रहा है
dirname "$0"
$ 0 स्क्रिप्ट का आदेश देने वाले कमांड के पहले भाग का प्रतिनिधित्व करता है (यह मूल रूप से तर्कों के बिना इनपुट कमांड है:
/some/path/./script argument1 argument2
$ 0 = "/ कुछ / पथ /./ स्क्रिप्ट"
dirname मूल रूप से अंतिम / एक स्ट्रिंग में पाता है और वहां इसे काट देता है। तो अगर तुम करते हो:
dirname /usr/bin/sha256sum
आपको मिलेगा: / usr / bin
यह उदाहरण अच्छी तरह से काम करता है क्योंकि / usr / bin / sha256sum एक उचित स्वरूपित पथ है लेकिन
dirname "/some/path/./script"
अच्छा काम नहीं करेगा और आपको देगा:
BASENAME="/some/path/." #which would crash your script if you try to use it as a path
कहते हैं कि आप अपनी स्क्रिप्ट के समान ही हैं और आप इसे इस आदेश के साथ लॉन्च करते हैं
./script
इस स्थिति में $ 0 होगा ।/cript और dirname $ 0 देगा:
. #or BASEDIR=".", again this will crash your script
का उपयोग करते हुए:
sh script
पूरा रास्ता इनपुट किए बिना भी एक BASEDIR = "देगा।"
रिश्तेदार निर्देशिकाओं का उपयोग करना:
../some/path/./script
का dirname $ 0 देता है:
../some/path/.
यदि आप / कुछ निर्देशिका में हैं और आप इस तरीके से स्क्रिप्ट को कॉल करते हैं (शुरुआत में / फिर से एक रिश्तेदार पथ की अनुपस्थिति पर ध्यान दें):
path/./script.sh
आपको dirname $ 0 के लिए यह मान मिलेगा:
path/.
और ./path/./cript (सापेक्ष पथ का दूसरा रूप) देता है:
./path/.
केवल दो स्थितियाँ जहाँ $ 0 काम करेगा, यदि उपयोगकर्ता किसी स्क्रिप्ट को लॉन्च करने के लिए श या टच का उपयोग करता है क्योंकि दोनों का परिणाम $ 0 होगा:
$0=/some/path/script
जो आपको एक मार्ग देगा जिसका उपयोग आप dirname के साथ कर सकते हैं।
समाधान
आपके पास उपरोक्त उल्लिखित स्थितियों में से हर एक का पता लगाने और उसका पता लगाने और उसके लिए एक सुधार लागू करने की आवश्यकता होगी:
#!/bin/bash
#this script will only work in bash, make sure it's installed on your system.
#set to false to not see all the echos
debug=true
if [ "$debug" = true ]; then echo "\$0=$0";fi
#The line below detect script's parent directory. $0 is the part of the launch command that doesn't contain the arguments
BASEDIR=$(dirname "$0") #3 situations will cause dirname $0 to fail: #situation1: user launches script while in script dir ( $0=./script)
#situation2: different dir but ./ is used to launch script (ex. $0=/path_to/./script)
#situation3: different dir but relative path used to launch script
if [ "$debug" = true ]; then echo 'BASEDIR=$(dirname "$0") gives: '"$BASEDIR";fi
if [ "$BASEDIR" = "." ]; then BASEDIR="$(pwd)";fi # fix for situation1
_B2=${BASEDIR:$((${#BASEDIR}-2))}; B_=${BASEDIR::1}; B_2=${BASEDIR::2}; B_3=${BASEDIR::3} # <- bash only
if [ "$_B2" = "/." ]; then BASEDIR=${BASEDIR::$((${#BASEDIR}-1))};fi #fix for situation2 # <- bash only
if [ "$B_" != "/" ]; then #fix for situation3 #<- bash only
if [ "$B_2" = "./" ]; then
#covers ./relative_path/(./)script
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/${BASEDIR:2}"; else BASEDIR="/${BASEDIR:2}";fi
else
#covers relative_path/(./)script and ../relative_path/(./)script, using ../relative_path fails if current path is a symbolic link
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/$BASEDIR"; else BASEDIR="/$BASEDIR";fi
fi
fi
if [ "$debug" = true ]; then echo "fixed BASEDIR=$BASEDIR";fi
यह एक-लाइनर बताता है कि शेल स्क्रिप्ट कहां है, इससे कोई फर्क नहीं पड़ता कि आप इसे चलाते हैं या यदि आपने इसे खट्टा किया है । इसके अलावा, यह किसी भी प्रतीकात्मक लिंक को हल करता है, अगर ऐसा है:
dir=$(dirname $(test -L "$BASH_SOURCE" && readlink -f "$BASH_SOURCE" || echo "$BASH_SOURCE"))
वैसे, मुझे लगता है कि आप / बिन / बैश का उपयोग कर रहे हैं ।
इतने सारे उत्तर, सभी प्रशंसनीय, प्रत्येक समर्थक और चोर के & थोड़े अलग उद्देश्यों के साथ (जो शायद प्रत्येक के लिए कहा जाना चाहिए)। यहाँ एक और समाधान है जो सभी प्रणालियों पर सभी स्पष्ट और सभी प्रणालियों पर काम करने का एक प्राथमिक उद्देश्य पूरा करता है, (bash संस्करणों के बारे में कोई धारणा नहीं), या readlink
याpwd
विकल्प के करता है, और यथोचित रूप से वही होता है जो आप होने की उम्मीद करते हैं (उदाहरण के लिए, सहानुभूति का समाधान करना एक है) दिलचस्प समस्या है, लेकिन आम तौर पर आप जो चाहते हैं वह नहीं होता है), पथ के मामलों में बढ़त जैसे मामलों को संभालते हैं, आदि, किसी भी त्रुटि को अनदेखा करता है और कोई समस्या होने पर एक डिफ़ॉल्ट डिफ़ॉल्ट का उपयोग करता है।
प्रत्येक घटक को एक अलग चर में संग्रहीत किया जाता है जिसे आप व्यक्तिगत रूप से उपयोग कर सकते हैं:
# script path, filename, directory
PROG_PATH=${BASH_SOURCE[0]} # this script's name
PROG_NAME=${PROG_PATH##*/} # basename of script (strip path)
PROG_DIR="$(cd "$(dirname "${PROG_PATH:-$PWD}")" 2>/dev/null 1>&2 && pwd)"
ब्लूड के जवाब से प्रेरित
read < <(readlink -f $0 | xargs dirname)
cd $REPLY
यह ट्रिक काम आना चाहिए:
echo `pwd`/`dirname $0`
यह बदसूरत लग सकता है कि यह कैसे लागू किया गया था और सीडब्ल्यूडी लेकिन आपको वहां जाना चाहिए जहां आपको जाने की आवश्यकता है (या आप स्ट्रिंग को ट्विक कर सकते हैं यदि आप परवाह करते हैं कि यह कैसा दिखता है)।
`pwd`/`dirname $0`
लेकिन अभी भी सहानुभूति पर विफल हो सकता है