बाश में $ (कमांड प्रतिस्थापन) के भीतर उद्धृत


126

मेरे बैश वातावरण में मैं रिक्त स्थान वाले चर का उपयोग करता हूं, और मैं कमांड प्रतिस्थापन के भीतर इन चर का उपयोग करता हूं। दुर्भाग्य से मुझे एसई पर जवाब नहीं मिला।

मेरे चर को उद्धृत करने का सही तरीका क्या है? और अगर मुझे ये नेस्टेड हैं तो मुझे यह कैसे करना चाहिए?

DIRNAME=$(dirname "$FILE")

या मैं प्रतिस्थापन के बाहर बोली?

DIRNAME="$(dirname $FILE)"

अथवा दोनों?

DIRNAME="$(dirname "$FILE")"

या मैं बैक-टिक्स का उपयोग करूं?

DIRNAME=`dirname "$FILE"`

ऐसा करने का सही तरीका क्या है? और अगर उद्धरण सही सेट हैं तो मैं आसानी से कैसे जांच सकता हूं?


इसे भी देखें - unix.stackexchange.com/questions/97560/…
ग्रीम


1
यह एक अच्छा प्रश्न है, लेकिन सभी मुद्दों को एम्बेडेड ब्लॉक्स के साथ दिया गया है, तो आप उन्हें उद्देश्य पर उपयोग करके जीवन को अपने आप में कठिन क्यों बनायेंगे?
जो

3
@ जो, एंबेडेड ब्लॉक्स के साथ आप फिल्नाम में स्पेस का मतलब रखते हैं? व्यक्तिगत रूप से मैं उनका उपयोग अक्सर नहीं करता हूं, लेकिन मैं अन्य लोगों की निर्देशिकाओं और फाइलों के साथ काम कर रहा हूं, जिनमें से अगर मैं रिक्त स्थान रखता हूं तो मुझे निश्चित नहीं है। इसके अलावा, मुझे लगता है कि इसे एक बार में ठीक करना बेहतर है ताकि मुझे भविष्य में परेशान न होना पड़े।
कज़िन कोकीन

4
हाँ। हम उन "अन्य लोगों" के साथ क्या करने जा रहे हैं? <जी>
जो

जवाबों:


188

सबसे खराब से बेहतरीन क्रम में:

  • DIRNAME="$(dirname $FILE)" अगर आप$FILE व्हाट्सएप या ग्लोबिंग कैरेक्टर चाहते हैं तो आप ऐसा नहीं करेंगे\[?*
  • DIRNAME=`dirname "$FILE"`तकनीकी रूप से सही है, लेकिन बैकस्टिक्स को कमांड विस्तार के लिए अनुशंसित नहीं किया जाता है क्योंकि उन्हें घोंसले में डालने पर अतिरिक्त जटिलता होती है।
  • DIRNAME=$(dirname "$FILE")सही है, लेकिन केवल इसलिए कि यह एक असाइनमेंट है । यदि आप किसी अन्य संदर्भ में कमांड प्रतिस्थापन का उपयोग करते हैं, जैसे कि export DIRNAME=$(dirname "$FILE")या du $(dirname "$FILE"), तो उद्धरण के अभाव में परेशानी का कारण होगा यदि विस्तार के परिणाम में व्हाट्सएप या ग्लोबिंग वर्ण होते हैं।
  • DIRNAME="$(dirname "$FILE")"अनुशंसित तरीका है। आप DIRNAME=कुछ और बदले बिना कमांड और स्पेस के साथ बदल सकते हैं, और dirnameसही स्ट्रिंग प्राप्त कर सकते हैं।

आगे भी सुधार करने के लिए:

  • DIRNAME="$(dirname -- "$FILE")"काम अगर $FILEएक पानी का छींटा के साथ शुरू होता है।
  • DIRNAME="$(dirname -- "$FILE"; printf x)" && DIRNAME="${DIRNAME%?x}"यहां तक ​​कि काम करता है भले ही $FILEएक newline के साथ समाप्त होता है, क्योंकि $()उत्पादन के अंत में newlines बंद कर देता है और dirnameपरिणाम के बाद एक नई पंक्ति आउटपुट करता है। शीश dirname, तुम अलग क्यों हो?

आप जितने चाहे कमांड एक्सपेंशन कर सकते हैं। आपके साथ $()हमेशा एक नया उद्धरण संदर्भ बनाया जाता है, ताकि आप इस तरह की चीजें कर सकें:

foo "$(bar "$(baz "$(ban "bla")")")"

आप बैकटिक्स के साथ कोशिश नहीं करना चाहते हैं।


3
मेरे प्रश्न का स्पष्ट उत्तर। जब मैं इन चरों को घोंसला देता हूं, तो क्या मैं अभी जैसे करता हूं, वैसा ही कर सकता हूं?
कज़िन कोकीन

3
क्या उद्धरण के भीतर एक कमांड सबस्टेशन के भीतर उद्धरणों के व्यवहार का विवरण देने वाला एक संदर्भ / संसाधन है?
AmadeusDrZaius

12
@AmadeusDrZaius " $()आप हमेशा एक नया उद्धरण संदर्भ बनाते हैं", इसलिए यह बाहरी उद्धरणों के बाहर की तरह है। जहाँ तक मुझे पता है, इसके लिए और कुछ भी नहीं है।
l0b0

4
@ l0b0 धन्यवाद, हाँ, मुझे आपका स्पष्टीकरण बहुत स्पष्ट लगा। मैं बस सोच रहा था कि क्या यह एक मैनुअल में भी था। मैंने इसे (अनौपचारिक रूप से) ऊनी तौर पर पाया । मुझे लगता है कि अगर आप ध्यान से प्रतिस्थापन के आदेश के बारे में पढ़ते हैं , तो आप इस तथ्य को परिणाम के रूप में प्राप्त कर सकते हैं।
AmadeusDrZaius

1
इसलिए नेस्टेड उद्धरण स्वीकार्य हैं, लेकिन वे हमें फेंक देते हैं क्योंकि अधिकांश सिंटैक्स रंग योजनाएं विशेष परिस्थितियों का पता नहीं लगाती हैं। साफ।
ल्यूक डेविस

19

आप हमेशा चर के प्रभाव को दिखा सकते हैं printf

शब्द विभाजन पर किया var1:

$ var1="hello     world"
$ printf '[%s]\n' $var1
[hello]
[world]

var1 उद्धृत, इसलिए कोई शब्द नहीं बंट रहा है:

$ printf '[%s]\n' "$var1"
[hello     world]

इसके var1अंदर शब्द विभाजन $(), के बराबर echo "hello" "world":

$ var2=$(echo $var1)
$ printf '[%s]\n' "$var2"
[hello world]

कोई शब्द नहीं बंट रहा है var1, न उद्धृत करने के साथ कोई समस्या $():

$ var2=$(echo "$var1")
$ printf '[%s]\n' "$var2"
[hello     world]

var1फिर से विभाजित शब्द :

$ var2="$(echo $var1)"
$ printf '[%s]\n' "$var2"
[hello world]

दोनों को उद्धृत करते हुए, सुनिश्चित करने का सबसे आसान तरीका।

$ var2="$(echo "$var1")"
$ printf '[%s]\n' "$var2"
[hello     world]

ग्लोबिंग की समस्या

किसी चर को उद्धृत न करने से उसकी सामग्री का विस्तार हो सकता है:

$ mkdir test; cd test; touch file1 file2
$ var="*"
$ printf '[%s]\n' $var
[file1]
[file2]
$ printf '[%s]\n' "$var"
[*]

ध्यान दें कि यह केवल चर के विस्तार के बाद होता है। असाइनमेंट के दौरान ग्लोब को उद्धृत करना आवश्यक नहीं है:

$ var=*
$ printf '[%s]\n' $var
[file1]
[file2]
$ printf '[%s]\n' "$var"
[*]

set -fइस व्यवहार को अक्षम करने के लिए उपयोग करें :

$ set -f
$ var=*
$ printf '[%s]\n' $var
[*]

और set +fइसे फिर से सक्षम करने के लिए:

$ set +f
$ printf '[%s]\n' $var
[file1]
[file2]

8
लोग यह भूल जाते हैं कि शब्द बंटवारा एकमात्र समस्या नहीं है, आप अपने उदाहरण को बदलना चाहते हैं ताकि var1='hello * world'ग्लोबिंग समस्या का भी वर्णन किया जा सके।
स्टीफन चेज़लस

10

स्वीकृत उत्तर के अलावा:

जबकि मैं आम तौर पर @ l0b0 के उत्तर से सहमत हूं , मुझे "सबसे खराब से बेहतर" सूची में नंगे बैकटिक्स के प्लेसमेंट पर संदेह है, कम से कम आंशिक रूप से उस धारणा का परिणाम है जो $(...)हर जगह उपलब्ध है। मुझे एहसास है कि सवाल बैश को निर्दिष्ट करता है, लेकिन ऐसे कई बार होते हैं जब बैश का मतलब निकलता है /bin/sh, जो कि वास्तव में पूर्ण बॉर्न अगेन शेल नहीं हो सकता है।

विशेष रूप से, सादे बॉर्न शेल को पता नहीं चलेगा कि क्या करना है $(...), इसलिए स्क्रिप्ट जो इसके साथ संगत होने का दावा करती हैं (जैसे, एक #!/bin/shशबंग लाइन के माध्यम से ) संभवतः गलत व्यवहार करेगी यदि वे वास्तव में "वास्तविक" द्वारा चलाए जाते हैं /bin/sh- यह है विशेष रुचि जब, कहते हैं, init स्क्रिप्ट का निर्माण, या पैकेजिंग पूर्व और बाद की स्क्रिप्ट, और एक आधार प्रणाली की स्थापना के दौरान एक आश्चर्यजनक जगह में उतर सकता है।

अगर उस चर में से कोई भी ऐसा लगता है जिसे आप इस चर के साथ करने की योजना बना रहे हैं, तो घोंसला बनाना वास्तव में स्क्रिप्ट की तुलना में चिंता का कम है, अनुमानतः चला। जब यह एक सरल पर्याप्त मामला है और पोर्टेबिलिटी एक चिंता का विषय है, भले ही मुझे उम्मीद है कि स्क्रिप्ट आमतौर पर सिस्टम पर चलती है जहां /bin/shबैश है, मैं अक्सर इस कारण से बैकटिक्स का उपयोग करने के लिए करता हूं, घोंसले के शिकार के बजाय कई असाइनमेंट के साथ।

यह सब कहने के बाद, गोले की सर्वव्यापकता, जो लागू होती है $(...)(बाश, डैश, एट अल।), प्रीटियर, आसान-से-घोंसले के साथ छड़ी करने के लिए हमें एक अच्छे स्थान पर छोड़ देती है, और ज्यादातर मामलों में, हाल ही में पसंद किए गए POSIX सिंटैक्स के लिए। सभी कारणों @ l0b0 का उल्लेख है।

एक तरफ: यह कभी-कभी StackOverflow पर भी दिखा है,


//, बहुत बढ़िया जवाब। मैं अतीत में / बिन / श के साथ भी पीछे की संगतता के मुद्दों में चला गया हूं। क्या आपको इस बारे में कोई सलाह है कि बैकवर्ड संगत तरीकों का उपयोग करके उसकी समस्या से कैसे निपटें?
नाथन बसानी

मेरे अनुभव में: कभी-कभी आपको बैकटिक्स को डॉलर के पैरा में संलग्न करने के लिए बदलने की आवश्यकता हो सकती है, और न कि एक बार कभी मदद करने (आवश्यक होने के लिए, विशिष्ट होने के लिए) को बैक्टिक्स में डॉलर के पैने को बदलने के लिए। मैं केवल अपने जावास्क्रिप्ट कोड में backticks लिखता हूं, और शेल कोड में नहीं।
स्टीवन लू
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.