शेल ब्रैकेट परीक्षण में त्रुटि जब स्ट्रिंग एक बाएं-कोष्ठक है


27

मैं इस तथ्य के बारे में आश्वस्त हुआ करता था कि स्ट्रिंग को उद्धृत करने से बचने के लिए स्ट्रिंग्स को उद्धृत करना हमेशा एक अच्छा अभ्यास है।

फिर मैं इस पार आया:

$ x='('
$ [ "$x" = '1' -a "$y" = '1' ]
bash: [: `)' expected, found 1

समस्या को अलग करने की कोशिश, एक ही त्रुटि हो रही है:

$ [ '(' = '1' -a '1' = '1' ]
bash: [: `)' expected, found 1

मैंने इस तरह की समस्या को हल किया:

[ "$x" = '1' ] && [ "$y" = '1' ]

फिर भी मुझे यह जानना होगा कि यहाँ क्या हो रहा है।


2
एक समाधान के रूप में, बैश में, आप उपयोग कर सकते हैं[[ "$x" = '1' && "$y" = '1' ]]
टेराडॉन

3
POSIX विनिर्देश परीक्षण के लिए स्पष्ट रूप से वर्णन करता है -aऔर -oइस कारण से अश्लील (जो कि [OB]उनके विनिर्देशन के बगल में सुपरस्क्रिप्ट है)। यदि आपने [ "$x" = 1 ] && [ "$y" = 1 ]इसके बजाय लिखा है , तो आप ठीक होंगे, और अच्छी तरह से परिभाषित / मानकीकृत व्यवहार के दायरे में अच्छी तरह से होंगे।
चार्ल्स डफी

6
यही कारण है कि लोग [ "x$x" = "x1" ]संचालकों के रूप में गलत व्याख्या किए जा रहे तर्कों को रोकने के लिए उपयोग करते थे।
जोनाथन लेफ्लर

@JonathanLeffler: अरे, आपने एक भी वाक्य के लिए मेरे जवाब की निंदा की, उचित नहीं! :) यदि कोई dashबैश के बजाय पोसिक्स शेल का उपयोग करता है , तो यह अभी भी एक उपयोगी अभ्यास है।
सांकेतिक पशु

मैं हर किसी को धन्यवाद देना चाहता हूं कि वह मेरे प्रश्न का उत्तर दे, वास्तव में लोगों की सराहना की :)! मैं अपने प्रश्न के लिए किए गए महत्वपूर्ण संपादन के लिए भी धन्यवाद देना चाहता हूं। इस मंच में प्रवेश करने से कभी-कभी मुझे अलकतरा से बचने का एक ही रोमांच मिलता है, गलत कदम का मतलब है आपका जीवन। वैसे भी मैं वास्तव में चाहता हूं कि मेरा धन्यवाद इस टिप्पणी के डिलीट होने से पहले आप तक पहुंच जाए
क्लाउडियो

जवाबों:


25

यह एक बहुत ही अस्पष्ट कोने का मामला है कि कोई एक बग पर विचार कर सकता है जिसमें परीक्षण [अंतर्निहित है; हालाँकि, यह [कई प्रणालियों पर उपलब्ध वास्तविक बाइनरी के व्यवहार से मेल खाता है । जहाँ तक मेरा बता सकते हैं, यह केवल कुछ मामलों और एक चर है कि एक से मेल खाता है एक मूल्य के होने को प्रभावित करता है [की तरह ऑपरेटर (, !, =, -e, और इतने पर।

मुझे समझाएं कि क्यों, और कैसे इसके चारों ओर बैश और पोसिक्स गोले में काम करना है।


स्पष्टीकरण:

निम्नलिखित को धयान मे रखते हुए:

x="("
[ "$x" = "(" ] && echo yes || echo no

कोई बात नहीं; उपरोक्त पैदावार में कोई त्रुटि नहीं है, और आउटपुट yes। इस तरह हम काम करने के लिए सामान की उम्मीद करते हैं। '1'यदि आप चाहें तो तुलना स्ट्रिंग को बदल सकते हैं , और इसका मूल्य x, और यह अपेक्षित रूप से काम करेगा।

ध्यान दें कि वास्तविक /usr/bin/[बाइनरी उसी तरह व्यवहार करती है। यदि आप चलाते हैं जैसे '/usr/bin/[' '(' = '(' ']'कि कोई त्रुटि नहीं है, क्योंकि कार्यक्रम यह पता लगा सकता है कि तर्क एकल स्ट्रिंग तुलना ऑपरेशन से मिलकर बनता है।

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

[ '1' = '1' ] && echo yes || echo no

आउटपुट yes, और स्पष्ट रूप से एक वैध अभिव्यक्ति है; लेकिन, अगर हम दोनों को मिला दें,

[ "$x" = "(" -a '1' = '1' ] && echo yes || echo no

बैश अभिव्यक्ति को अस्वीकार कर देता है यदि और केवल अगर xहै (या !

यदि हम वास्तविक [कार्यक्रम का उपयोग करके ऊपर चला रहे थे , अर्थात

'/usr/bin/[' "$x" = "(" -a '1' = '1' ] && echo yes || echo no

त्रुटि समझ में आ जाएगी: चूंकि शेल परिवर्तनीय प्रतिस्थापन करता है, /usr/bin/[बाइनरी केवल मापदंडों को प्राप्त करता है ( = ( -a 1 = 1और समाप्त करता है ], यह समझ में नहीं आता है कि क्या खुले कोष्ठक एक उप-अभिव्यक्ति शुरू करते हैं या नहीं, इसमें एक और ऑपरेशन शामिल है। निश्चित रूप से, इसे दो स्ट्रिंग तुलनाओं के रूप में पार्स करना संभव है, लेकिन इसे लालच के साथ ऐसा करना संभव है कि जब छोटे-छोटे उप-अभिव्यक्तियों के साथ उचित भावों को लागू किया जाए तो यह समस्या हो सकती है।

समस्या, वास्तव में, यह है कि शेल [बिल्ट-इन उसी तरह से व्यवहार करता है, जैसे कि उसने xअभिव्यक्ति की जांच करने से पहले मूल्य का विस्तार किया हो ।

(ये अस्पष्टताएं, और चर विस्तार से संबंधित अन्य, एक बड़ा कारण था कि बैश ने क्यों लागू किया और अब [[ ... ]]इसके बजाय परीक्षण का उपयोग करने की अनुशंसा करता है ।)


वर्कअराउंड तुच्छ है, और अक्सर पुराने shगोले का उपयोग करके स्क्रिप्ट में देखा जाता है । आप एक "सुरक्षित" वर्ण जोड़ते हैं, अक्सर x, स्ट्रिंग के सामने (दोनों मूल्यों की तुलना की जा रही है), यह सुनिश्चित करने के लिए कि अभिव्यक्ति एक स्ट्रिंग तुलना के रूप में पहचानी जाती है:

[ "x$x" = "x(" -a "x$y" = "x1" ]

1
मैं [बिल्ट-इन बग के व्यवहार को नहीं कहूंगा । यदि कुछ है, तो यह एक अंतर्निहित डिजाइन दोष है। [[एक शेल कीवर्ड है , न कि केवल एक अंतर्निहित कमांड, इसलिए यह उद्धरण हटाने से पहले चीजों को देखने के लिए मिलता है, और वास्तव में सामान्य शब्द-विभाजन को ओवरराइड करता है। उदाहरण के [[ $x == 1 ]]लिए उपयोग करने की आवश्यकता नहीं है "$x", क्योंकि एक [[संदर्भ सामान्य से अलग है। वैसे भी, यह है कि कैसे [[के नुकसान से बचने में सक्षम है [। POSIX को [जिस तरह से व्यवहार करना पड़ता है, उसे करना पड़ता है, और bash ज्यादातर POSIX का पालन किए बिना भी होता है --posix, इसलिए [कीवर्ड में बदलना बदसूरत है।
पीटर कॉर्ड्स

POSIX द्वारा आपका वर्कअराउंड अनुशंसित नहीं है। बस दो कॉल का उपयोग करें [
वाइल्डकार्ड 21

@PeterCordes: काफी सही; अच्छी बात। (मैं शायद अपने पहले पैराग्राफ में परिभाषित के बजाय डिज़ाइन किया गया होना चाहिए , लेकिन POSIX से पहले के इतिहास से बोझिल व्यवहार किया जा रहा है, मैंने इसके बजाय बाद वाला शब्द चुना।) मैं व्यक्तिगत रूप से अपने उदाहरण लिपियों में उपयोग करने से बचता हूं, लेकिन केवल इसलिए कि यह है। उद्धृत अनुशंसा के अपवाद के बारे में मैं हमेशा वीणा करता हूं (क्योंकि उद्धरण को छोड़ना मेरे द्वारा देखे जाने वाले स्क्रिप्ट बग के लिए सबसे आम कारण है), और मैंने यह समझाने के लिए एक सरल पैराग्राफ के बारे में नहीं सोचा है कि मेरी उद्धरण सिफारिश किए बिना, नियमों का अपवाद क्यों है। संदिग्ध। [[[[[
सांकेतिक पशु

@Wildcard: नहीं। POSIX इस प्रथा के खिलाफ सिफारिश नहीं करता है , और यही मायने रखता है। सिर्फ इसलिए कि एक प्राधिकरण इस अभ्यास की सिफारिश करने के लिए नहीं होता है, यह बुरा नहीं बनाता है। दरअसल, जैसा कि मैं इंगित करता हूं, यह ऐतिहासिक अभ्यास है जिसका उपयोग shलिपियों में किया जाता है , जो कि POSIX मानकीकरण से पहले होता है। परीक्षणों में / -aया -oतार्किक संचालकों के अवमूल्यन का उपयोग करना / [अधिक कुशल है जो अभिव्यक्ति की श्रृंखला पर निर्भर है (के माध्यम से &&और ||); यह सिर्फ वर्तमान मशीनों पर है, अंतर अप्रासंगिक है।
सांकेतिक पशु

@Wildcard: हालांकि, मैं व्यक्तिगत रूप से श्रृंखला के लिए परीक्षण अभिव्यक्ति का उपयोग करते पसंद करते हैं &&और ||है, लेकिन कारण है, यह आसान हमें (पढ़ें, समझते हैं, और यदि / जब आवश्यक संशोधित) को बनाए रखने कीड़े को शुरू करने के बिना उन्हें मनुष्य के लिए बनाता है। इसलिए, मैं आपके सुझाव की आलोचना नहीं कर रहा हूं, बल्कि केवल सुझाव के पीछे तर्क है। (बहुत इसी तरह के कारणों के लिए, .LT., .GE., FORTRAN 77 में आदि तुलना ऑपरेटरों और अधिक मानव के अनुकूल संस्करण मिल गया <, >=, बाद के संस्करणों में आदि।)
नाममात्र पशु

11

[उर्फ testदेखता है:

 argc: 1 2 3 4  5 6 7 8
 argv: ( = 1 -a 1 = 1 ]

testकोष्ठक में उपमेय स्वीकार करता है; इसलिए यह सोचता है कि बाईं कोष्ठक एक उप-कपट खोलता है और इसे पार्स करने की कोशिश कर रहा है; पार्सर =उपप्रकार में पहली चीज के रूप में देखता है और सोचता है कि यह एक अंतर्निहित स्ट्रिंग-लंबाई परीक्षण है, इसलिए यह खुश है; उपपरिवर्तन तो एक सही कोष्ठक द्वारा पीछा किया जाना चाहिए, और इसके बजाय पार्सर के 1बजाय पाता है )। और यह शिकायत करता है।

जब testवास्तव में तीन तर्क होते हैं, और मध्य तर्क मान्यता प्राप्त संचालकों में से एक है, तो यह उस ऑपरेटर को 1 और 3 तर्कों में लागू करता है, बिना कोष्ठक में उप-संदर्भों की तलाश के।

पूर्ण विवरण देखने के man bashलिए, खोजें test expr

निष्कर्ष: पार्सिंग एल्गोरिथम का उपयोग testजटिल है। केवल सरल अभिव्यक्तियों का उपयोग करें और शेल ऑपरेटरों का उपयोग करें !, &&और ||उन्हें संयोजित करने के लिए।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.