पैट्रिस ने अपने उत्तर में समस्या के स्रोत की पहचान की , लेकिन अगर आप जानना चाहते हैं कि वहां से कैसे प्राप्त किया जाए तो आप इसे प्राप्त करते हैं, तो यहां एक लंबी कहानी है।
एक प्रक्रिया की वर्तमान कार्यशील निर्देशिका कुछ भी नहीं है जिसे आप बहुत जटिल समझेंगे। यह उस प्रक्रिया का एक गुण है, जो एक प्रकार की निर्देशिका की फ़ाइल के लिए एक हैंडल है, जहां रिश्तेदार पथ (प्रक्रिया द्वारा किए गए सिस्टम कॉल) से शुरू होते हैं। किसी सापेक्ष पथ को हल करते समय, कर्नेल को उस वर्तमान निर्देशिका के लिए (a) पूर्ण पथ जानने की आवश्यकता नहीं होती है, यह केवल सापेक्ष पथ के पहले घटक को खोजने के लिए उस निर्देशिका फ़ाइल में निर्देशिका प्रविष्टियों को पढ़ता है (और ..
किसी अन्य की तरह है) उस संबंध में फ़ाइल) और वहाँ से जारी है।
अब, एक उपयोगकर्ता के रूप में, आप कभी-कभी यह जानना पसंद करते हैं कि निर्देशिका ट्री में कहाँ है। अधिकांश यूनियनों के साथ, निर्देशिका पेड़ एक पेड़ है, जिसमें कोई लूप नहीं है। यही है, पेड़ की जड़ ( /
) से किसी भी फ़ाइल में केवल एक ही रास्ता है । उस पथ को आम तौर पर विहित पथ कहा जाता है।
वर्तमान कार्यशील निर्देशिका का मार्ग प्राप्त करने के लिए, एक प्रक्रिया को करने के लिए बस चलना है (अच्छी तरह से नीचे अगर आप नीचे एक पेड़ को उसकी जड़ के साथ देखना पसंद करते हैं) पेड़ को जड़ तक वापस जाना, नोड्स के नाम खोजना रास्ते में।
उदाहरण के लिए, एक प्रक्रिया जो यह पता लगाने की कोशिश कर रही है कि इसकी वर्तमान निर्देशिका है /a/b/c
, निर्देशिका को खोलेगी ..
(सापेक्ष पथ, इसलिए ..
वर्तमान निर्देशिका में प्रविष्टि है) और उसी इनोड संख्या के साथ टाइप निर्देशिका की एक फ़ाइल की .
तलाश करें, यह पता करें कि c
मैच, तब तक खुलता है ../..
और जब तक यह नहीं मिलता है /
। वहां कोई अस्पष्टता नहीं है।
यह वही है जो getwd()
या getcwd()
सी कार्य करता है या कम से कम करने के लिए उपयोग किया जाता है।
आधुनिक लिनक्स जैसी कुछ प्रणालियों पर, वर्तमान निर्देशिका में कैनोनिकल पथ को वापस करने के लिए एक सिस्टम कॉल है जो कर्नेल स्पेस में उस लुकअप को करता है (और आपको अपने वर्तमान निर्देशिका को खोजने की अनुमति देता है, भले ही आपने इसके सभी घटकों तक पहुंच न पढ़ी हो) , और यही getcwd()
वहां कॉल है। आधुनिक लिनक्स पर, आप एक रीडलिंक () के माध्यम से वर्तमान निर्देशिका का पथ भी पा सकते हैं /proc/self/cwd
।
वर्तमान निर्देशिका में वापसी करते समय अधिकांश भाषाएं और शुरुआती गोले क्या करते हैं।
आपके मामले में, आप कॉल कर सकते हैं cd a
हो सकता है के रूप में कई बार के रूप में आप चाहते हैं, क्योंकि यह करने के लिए एक सिमलिंक है, .
, वर्तमान निर्देशिका परिवर्तन नहीं करता है तो सभी की getcwd()
, pwd -P
, python -c 'import os; print os.getcwd()'
, perl -MPOSIX -le 'print getcwd'
आपकी वापसी होगी ${HOME}
।
अब, सिम्बलिंक्स को वह सब मिल गया।
symlinks
निर्देशिका ट्री में कूदता है। में /a/b/c
, अगर /a
या /a/b
या /a/b/c
एक सिमलिंक, तो के विहित मार्ग है /a/b/c
कुछ पूरी तरह से अलग हो जाएगा। विशेष रूप से, ..
प्रवेश /a/b/c
आवश्यक नहीं है /a/b
।
बॉर्न शेल में, यदि आप करते हैं:
cd /a/b/c
cd ..
या और भी:
cd /a/b/c/..
इसमें कोई गारंटी नहीं है कि आप अंत करेंगे /a/b
।
बिलकुल इसके जैसा:
vi /a/b/c/../d
आवश्यक रूप से समान नहीं है:
vi /a/b/d
ksh
किसी भी तरह से काम करने के लिए एक तार्किक वर्तमान कार्यशील निर्देशिका की अवधारणा पेश की । लोगों को इसकी आदत हो गई और POSIX ने उस व्यवहार को निर्दिष्ट किया, जिसका अर्थ है कि आजकल अधिकांश गोले ऐसा करते हैं:
के लिए cd
और pwd
अंतर्निहित आदेश ( और केवल उनके लिए (हालांकि यह भी के लिए popd
/ pushd
गोले उन्हें) है पर), खोल वर्तमान कार्यशील निर्देशिका का अपना विचार रखता है। इसे $PWD
विशेष चर में संग्रहीत किया जाता है ।
जब तुम करोगे:
cd c/d
यदि समरूप हैं c
या c/d
हैं, जबकि $PWD
सम्मिलित हैं /a/b
, तो यह c/d
अंत तक लागू होता $PWD
है /a/b/c/d
। और जब आप करते हैं:
cd ../e
करने के बजाय chdir("../e")
, यह करता है chdir("/a/b/c/e")
।
और pwd
कमांड केवल $PWD
चर की सामग्री को वापस करता है ।
यह इंटरेक्टिव गोले में उपयोगी है क्योंकि pwd
वर्तमान निर्देशिका के लिए एक पथ को आउटपुट करता है जो आपको वहां कैसे मिला है और जब तक आप केवल ..
तर्कों में उपयोग करते हैं cd
और अन्य आदेशों को नहीं, यह आपको आश्चर्यचकित करने की संभावना कम है, क्योंकि cd a; cd ..
या cd a/..
आम तौर पर आपको वापस मिल जाएगा। तुम कहाँ थे
अब, $PWD
जब तक कि आप एक संशोधित नहीं करते हैं cd
। अगली बार जब तक आप फोन करते हैं cd
या pwd
बहुत सारी चीजें हो सकती हैं, तब तक किसी भी घटक का $PWD
नाम बदला जा सकता है। वर्तमान निर्देशिका कभी नहीं बदलती (यह हमेशा एक ही इनोड है, हालांकि इसे हटाया जा सकता है), लेकिन निर्देशिका ट्री में इसका पथ पूरी तरह से बदल सकता है। getcwd()
वर्तमान निर्देशिका की गणना हर बार निर्देशिका पेड़ के नीचे चलने से होती है, इसलिए इसकी जानकारी हमेशा सटीक होती है, लेकिन POSIX गोले द्वारा लागू की गई तार्किक निर्देशिका के लिए, जानकारी $PWD
बासी हो सकती है। इसलिए दौड़ने पर cd
या pwd
, कुछ गोले उस पर पहरा देना चाहते हैं।
उस विशेष उदाहरण में, आप अलग-अलग गोले के साथ अलग-अलग व्यवहार देखते हैं।
कुछ ksh93
लोग समस्या को पूरी तरह से अनदेखा कर देते हैं, इसलिए आपके कॉल करने पर भी गलत जानकारी वापस आ जाएगी cd
(और आप उस व्यवहार को नहीं देखेंगे जो आप bash
वहाँ देख रहे हैं )।
कुछ लोग ऐसा करते हैं bash
या zsh
जाँचते हैं कि $PWD
अभी भी चालू निर्देशिका के लिए एक रास्ता है cd
, लेकिन नहीं pwd
।
pdksh दोनों पर जाँच करता है pwd
और cd
(लेकिन pwd
अपडेट नहीं करता है $PWD
)
ash
(कम से कम एक डेबियन पर होता है) की जांच नहीं करता है, और जब आप ऐसा करेंगे cd a
, यह वास्तव में करता है cd "$PWD/a"
, इसलिए यदि वर्तमान निर्देशिका बदल गया है और $PWD
वर्तमान निर्देशिका के लिए नहीं रह अंक, यह वास्तव में करने के लिए नहीं बदलेगा a
निर्देशिका मौजूदा निर्देशिका में , लेकिन $PWD
यदि इसमें कोई त्रुटि है (यदि वह मौजूद नहीं है तो वापस लौटें)।
यदि आप इसके साथ खेलना चाहते हैं, तो आप कर सकते हैं:
cd
mkdir -p a/b
cd a
pwd
mv ~/a ~/b
pwd
echo "$PWD"
cd b
pwd; echo "$PWD"; pwd -P # (and notice the bug in ksh93)
विभिन्न गोले में।
आपके मामले में, जब से आप उपयोग कर रहे हैं bash
, एक के बाद cd a
, bash
जांचता है कि $PWD
अभी भी वर्तमान निर्देशिका को इंगित करता है । ऐसा करने के लिए, यह अपने इनोड संख्या की जांच करने और इसके साथ तुलना करने stat()
के $PWD
लिए मूल्य पर कॉल करता है .
।
लेकिन जब $PWD
रास्ते की तलाश में बहुत सारे सिम्बलिंक्स को हल करना शामिल होता है stat()
, तो वह एक त्रुटि के साथ लौटता है, इसलिए शेल यह जांच नहीं कर सकता है कि क्या $PWD
अभी भी वर्तमान निर्देशिका से मेल खाती है, इसलिए यह उसके साथ फिर से गणना करता है getcwd()
और $PWD
तदनुसार अपडेट करता है ।
अब, पैट्रिस के जवाब को स्पष्ट करने के लिए, कि एक मार्ग को देखते हुए सहानुभूति की संख्या की जांच एक मार्ग को देखने के लिए होती है, जो कि सिम्लिंक डॉप्स के खिलाफ गार्ड है। सबसे सरल लूप के साथ बनाया जा सकता है
rm -f a b
ln -s a b
ln -s b a
उस सुरक्षित गार्ड के बिना, एक पर cd a/x
, सिस्टम को यह पता लगाना होगा कि a
लिंक कहाँ है, यह पाता है b
और यह एक सिमलिंक है जो लिंक करता है a
, और यह अनिश्चित काल तक चलता रहेगा। उस से बचाव के लिए सबसे सरल तरीका है कि एक अनियंत्रित संख्या से अधिक सीमलिंक को हल करने के बाद छोड़ देना।
अब तार्किक वर्तमान कार्यशील निर्देशिका पर वापस लौटें और यह इतनी अच्छी सुविधा क्यों नहीं है। यह महसूस करना महत्वपूर्ण है कि यह केवल cd
शेल में है और अन्य कमांड के लिए नहीं।
उदाहरण के लिए:
cd -- "$dir" && vi -- "$file"
हमेशा समान नहीं है:
vi -- "$dir/$file"
इसीलिए आप कभी-कभी पाएंगे कि लोग cd -P
भ्रम से बचने के लिए हमेशा लिपियों में उपयोग करने की सलाह देते हैं (आप नहीं चाहते कि आपका सॉफ़्टवेयर ../x
अन्य आदेशों से भिन्नता के तर्क को केवल इसलिए हैंडल करे क्योंकि यह किसी अन्य भाषा के बजाय शेल में लिखा गया है)।
-P
विकल्प को अक्षम करने के लिए है तार्किक निर्देशिका से निपटने तो cd -P -- "$var"
वास्तव में फोन करता है chdir()
की सामग्री पर $var
(छोड़कर जब $var
है -
लेकिन यह है कि एक और कहानी है)। और एक के बाद cd -P
, $PWD
एक विहित पथ होगा।