$ (कमांड $ arg) को उद्धृत करने का सही तरीका क्या है?


17

यह इस समय को सुलझाने के लिए उच्च समय है जो मुझे वर्षों से परेशान कर रहा है ...

मैं समय-समय पर इससे मिलता रहा और सोचा कि यही रास्ता है:

$(comm "$(arg)")

और मुझे लगा कि मेरे विचार को अनुभव से बहुत समर्थन मिला। लेकिन मुझे अब यकीन नहीं है। शेलचेक अपना दिमाग भी नहीं बना सकता है। यह दोनों है:

"$(dirname $0)"/stop.bash
           ^-- SC2086: Double quote to prevent globbing and word splitting.

तथा:

$(dirname "$0")/stop.bash
^-- SC2046: Quote this to prevent word splitting.

इसके पीछे क्या तर्क है?

(यह शेलचेक संस्करण 0.4.4 है, btw।)


1
सभी प्रतिस्थापन उद्धरण।
इग्नासियो वाज़केज़-अब्राम्स

3
ऐसे ही "$(dirname "$0")"/stop.bash:? यह काम करने लगता है ... कहानी क्या है?

1
bash यह जानने के लिए काफी स्मार्ट है कि संदर्भ कब बदल गया है।
इग्नासियो वाज़केज़-अब्राम्स

1
इसके बारे में इस तरह से सोचें shell_level_1 $(shell_level_2) shell_level_1:: जब आप अंदर होते हैं, $(....)तो आप शेल के "सलेवल" में प्रवेश करते हैं, लेकिन क्या आप इसमें लिख सकते हैं जैसे कि आप प्राथमिक स्तर पर थे (यानी, आप "इसके बजाय सीधे लिख सकते हैं \", आदि)। ex: touch "/tmp/a file" ; echo "its size is: $(find "/tmp/a file" -ls | awk '{print $5}) ..." : if you used backticks you'd have to find \ "/ tmp / a file \" `and print \$5। बिना $(...)किसी आवश्यकता के: शेल नए स्तर पर लागू होता है और आप सीधे लिख सकते हैं जैसे कि आपका दुभाषिया अब उस स्तर पर भी है।
ओलिवियर दुलैक

"शेलचेक अपना दिमाग भी नहीं बना सकता है।" - दो रनों के दो अलग-अलग संदेश होते हैं और अलग-अलग स्थानों पर इंगित होते हैं। यह दोनों चाहते हैं।
इज़्काता

जवाबों:


45

आपको उपयोग करने की आवश्यकता है "$(somecmd "$file")"

उद्धरण के बिना, एक स्थान के साथ एक पथ को तर्क में विभाजित किया somecmdजाएगा, और यह गलत फ़ाइल को लक्षित करेगा। तो आपको अंदर के उद्धरण चाहिए।

आउटपुट के किसी भी स्थान में somecmdविभाजन के कारण भी होंगे, इसलिए आपको पूरे कमांड प्रतिस्थापन के बाहर उद्धरणों की आवश्यकता होगी।

कमांड प्रतिस्थापन के अंदर उद्धरणों का इसके बाहर के उद्धरणों पर कोई प्रभाव नहीं पड़ता है। बैश का अपना संदर्भ मैनुअल इस पर बहुत स्पष्ट नहीं है, लेकिन बैशगाइड ने स्पष्ट रूप से इसका उल्लेख किया हैPOSIX में पाठ भी ऐसा करना आवश्यक हो, के रूप में "किसी वैध खोल स्क्रिप्ट" अंदर की अनुमति दी है $(...):

$(command)फॉर्म के साथ , खुले कोष्ठक के मिलान समापन कोष्ठक के बाद सभी वर्ण कमांड का गठन करते हैं। किसी भी मान्य शेल स्क्रिप्ट का उपयोग कमांड के लिए किया जा सकता है, केवल एक स्क्रिप्ट को छोड़कर जो अप्रत्यक्ष परिणाम पैदा करता है।


उदाहरण:

$ file="./space here/foo"

ए। कोई उद्धरण, dirnameप्रक्रियाएं दोनों ./spaceऔर here/foo:

$ printf "<%s>\n" $(dirname $file)
<.>
<here>

ख। अंदर उद्धरण, dirnameप्रक्रियाएं ./space here/foo, देना ./space here, जो दो में विभाजित है:

$ printf "<%s>\n" $(dirname "$file")
<./space>
<here>

सी। बाहर उद्धरण, dirnameदोनों प्रक्रियाओं ./spaceऔर here/foo, अलग लाइनों पर आउटपुट, लेकिन अब दो लाइनें एक एकल तर्क बनाती हैं :

$ printf "<%s>\n" "$(dirname $file)"
<.
here>

घ। अंदर और बाहर दोनों को उद्धृत करता है, इससे सही उत्तर मिलता है:

$ printf "<%s>\n" "$(dirname "$file")"
<./space here>

(यदि संभवत: यह आसान होता अगर dirnameकेवल पहले तर्क को संसाधित किया जाता, लेकिन यह मामलों के बीच अंतर को प्रदर्शित नहीं करता है a और c)।

ध्यान दें कि dirname(संभवत: दूसरों के साथ) आपको भी जोड़ना होगा --, फ़ाइल नाम को एक डैश के साथ शुरू करने के लिए ऐसा होने पर विकल्प के रूप में लेने से रोकने के लिए, इसलिए उपयोग करें "$(dirname -- "$file")"


16
नोट: सामान्य तौर पर, उद्धरण को कोसने में घोंसला नहीं बनाते हैं; लेकिन इस मामले में, $( )एक नया संदर्भ बनाता है, इसलिए इसके अंदर के उद्धरण इसके बाहर के उद्धरण से स्वतंत्र होते हैं। और आप आम तौर पर दोनों संदर्भों में उद्धरण चाहते हैं।
गॉर्डन डेविसन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.