दोनों के पास अपने झगड़े हैं, दुर्भाग्य से।
दोनों POSIX द्वारा आवश्यक हैं, इसलिए उनके बीच का अंतर पोर्टेबिलिटी चिंता का विषय नहीं है।
उपयोगिताओं का उपयोग करने का सादा तरीका है
base=$(basename -- "$filename")
dir=$(dirname -- "$filename")
चर प्रतिस्थापन के आसपास दोहरे उद्धरण चिह्नों पर ध्यान दें, हमेशा की तरह, और --
कमांड के बाद भी , यदि फ़ाइल का नाम डैश के साथ शुरू होता है (अन्यथा कमांड विकल्प के रूप में फ़ाइल नाम की व्याख्या करेगा)। यह अभी भी एक किनारे के मामले में विफल रहता है, जो दुर्लभ है लेकिन दुर्भावनापूर्ण उपयोगकर्ता द्वारा मजबूर किया जा सकता है: कमांड प्रतिस्थापन नए सिरे से पीछे हटता है। इसलिए यदि एक फ़ाइल नाम कहा जाता है, foo/bar
तो इसके बजाय base
सेट किया bar
जाएगा bar
। वर्कअराउंड नॉन-न्यूलाइन कैरेक्टर जोड़ना और कमांड प्रतिस्थापन के बाद इसे स्ट्रिप करना है:
base=$(basename -- "$filename"; echo .); base=${base%.}
dir=$(dirname -- "$filename"; echo .); dir=${dir%.}
पैरामीटर प्रतिस्थापन के साथ, आप अजीब पात्रों के विस्तार से संबंधित किनारे के मामलों में नहीं चलते हैं, लेकिन स्लैश चरित्र के साथ कई कठिनाइयां हैं। एक चीज़ जो एज केस नहीं है, वह यह है कि डायरेक्टरी पार्ट की गणना करने के लिए उस केस के लिए अलग कोड की आवश्यकता होती है जहाँ कोई नहीं है /
।
base="${filename##*/}"
case "$filename" in
*/*) dirname="${filename%/*}";;
*) dirname=".";;
esac
किनारे का मामला तब होता है जब एक अनुगामी स्लेश होता है (मूल निर्देशिका के मामले सहित, जो सभी स्लैश है)। basename
और dirname
आदेशों बंद पट्टी ट्रेलिंग स्लैश से पहले वे अपने काम करते हैं। यदि आप POSIX निर्माणों से चिपके रहते हैं, तो एक बार में पीछे चल रहे स्लैश को हटाने का कोई तरीका नहीं है, लेकिन आप इसे दो चरणों में कर सकते हैं। आपको उस मामले पर ध्यान देने की आवश्यकता है जब इनपुट में स्लैश के अलावा कुछ भी न हो।
case "$filename" in
*/*[!/]*)
trail=${filename##*[!/]}; filename=${filename%%"$trail"}
base=${filename##*/}
dir=${filename%/*};;
*[!/]*)
trail=${filename##*[!/]}
base=${filename%%"$trail"}
dir=".";;
*) base="/"; dir="/";;
esac
यदि आपको पता है कि आप एक किनारे के मामले में नहीं हैं (उदाहरण के find
लिए प्रारंभिक बिंदु के अलावा एक परिणाम हमेशा एक निर्देशिका हिस्सा होता है और कोई अनुगामी नहीं होता है /
) तो पैरामीटर विस्तार स्ट्रिंग हेरफेर सीधा होता है। यदि आपको सभी किनारे के मामलों का सामना करने की आवश्यकता है, तो उपयोगिताओं का उपयोग करना आसान है (लेकिन धीमा)।
कभी कभी, आप के इलाज के लिए चाहते हो सकता है foo/
की तरह foo/.
के बजाय की तरह foo
। यदि आप एक निर्देशिका प्रविष्टि पर अभिनय कर रहे हैं तो foo/
माना जाता है कि यह समकक्ष है foo/.
, नहीं foo
; जब foo
किसी निर्देशिका की प्रतीकात्मक कड़ी होती है तो इससे फर्क पड़ता है: foo
प्रतीकात्मक लिंक का foo/
अर्थ है, लक्ष्य निर्देशिका का अर्थ है। उस स्थिति में, पीछे चलने वाले स्लैश वाले पथ का बेसनेम लाभप्रद रूप से है .
, और पथ का अपना स्वयं का नाम हो सकता है।
case "$filename" in
*/) base="."; dir="$filename";;
*/*) base="${filename##*/}"; dir="${filename%"$base"}";;
*) base="$filename"; dir=".";;
esac
तेज़ और विश्वसनीय विधि अपने इतिहास के संशोधक के साथ zsh का उपयोग करना है (यह पहली स्ट्रैपिंग स्लैशिंग है , जैसे कि यूटिलिटीज़):
dir=$filename:h base=$filename:t
¹ जब तक आप सोलारिस 10 और पुराने के पूर्व-पॉसिक्स गोले का उपयोग नहीं कर रहे हैं /bin/sh
(जो कि अभी भी उत्पादन में मशीनों पर पैरामीटर विस्तार स्ट्रिंग हेरफेर सुविधाओं का अभाव है - लेकिन sh
स्थापना में हमेशा एक POSIX शेल कहा जाता है, केवल यह है /usr/xpg4/bin/sh
, नहीं /bin/sh
)।
Submit उदाहरण के लिए: foo
फ़ाइल अपलोड सेवा नामक एक फ़ाइल सबमिट करें जो इसके विरुद्ध सुरक्षा नहीं करती है, फिर इसे हटाएं और foo
इसके बजाय हटाने का कारण बनें
base=$(basename -- "$filename"; echo .); base=${base%.}; dir=$(dirname -- "$filename"; echo .); dir=${dir%.}
? मैं ध्यान से पढ़ रहा था और मैंने आपको किसी भी कमियों का उल्लेख नहीं किया।