मैं बैश में वाइल्डकार्ड / तारांकन चरित्र से कैसे बच सकता हूं?


136

उदाहरण के लिए:

me$ FOO="BAR * BAR"
me$ echo $FOO
BAR file1 file2 file3 file4 BAR

और \भागने चरित्र का उपयोग :

me$ FOO="BAR \* BAR"
me$ echo $FOO
BAR \* BAR

मैं स्पष्ट रूप से कुछ बेवकूफ कर रहा हूँ।

मुझे आउटपुट कैसे मिलेगा BAR * BAR?

जवाबों:


139

जब सेटिंग $FOOपर्याप्त न हो तो उद्धरण देना । आपको चर संदर्भ को भी उद्धृत करना होगा:

me$ FOO="BAR * BAR"
me$ echo "$FOO"
BAR * BAR

8
यह रहस्यमय है, यह क्यों है? क्या हो रहा है?
टॉफूटिम

क्योंकि चर का विस्तार
डैनियल

103

संक्षिप्त जवाब

जैसे दूसरों ने कहा है - आपको हमेशा अजीब व्यवहार को रोकने के लिए चर का उद्धरण देना चाहिए। तो इको "$ फू" की बजाय सिर्फ इको $ फू का उपयोग करें

लंबा जवाब

मुझे लगता है कि यह उदाहरण आगे की व्याख्या करता है क्योंकि इससे कहीं अधिक चल रहा है क्योंकि यह उसके चेहरे पर लग सकता है।

मैं देख सकता हूं कि आपका भ्रम कहां है क्योंकि आपने अपना पहला उदाहरण चलाने के बाद शायद आपने खुद से सोचा था कि शेल स्पष्ट रूप से कर रहा है:

  1. व्यास विस्तार
  2. फ़ाइल नाम विस्तार

तो अपने पहले उदाहरण से:

me$ FOO="BAR * BAR"
me$ echo $FOO

पैरामीटर विस्तार के बराबर है:

me$ echo BAR * BAR

और फ़ाइल नाम विस्तार के बराबर है:

me$ echo BAR file1 file2 file3 file4 BAR

और यदि आप केवल echo BAR * BARकमांड लाइन में टाइप करते हैं, तो आप देखेंगे कि वे समकक्ष हैं।

तो आप शायद अपने आप को "अगर मैं * से बचता हूं, तो मैं फ़ाइल नाम के विस्तार को रोक सकता हूं"

तो अपने दूसरे उदाहरण से:

me$ FOO="BAR \* BAR"
me$ echo $FOO

पैरामीटर विस्तार के बाद के बराबर होना चाहिए:

me$ echo BAR \* BAR

और फ़ाइल नाम के विस्तार के बराबर होना चाहिए:

me$ echo BAR \* BAR

और यदि आप सीधे कमांड लाइन में "इको बार \ * बार" टाइप करने की कोशिश करते हैं, तो यह वास्तव में "BAR * BAR" प्रिंट करेगा क्योंकि फ़ाइल नाम के विस्तार से बच जाता है।

तो $ फू का उपयोग क्यों नहीं किया?

ऐसा इसलिए है क्योंकि इसमें तीसरा विस्तार है - उद्धरण हटाना। बैश मैनुअल उद्धरण हटाने से है:

पूर्ववर्ती विस्तार के बाद, वर्णों के सभी अनियोजित घटनाएं '\', '' 'और' '' 'जिसके परिणामस्वरूप उपरोक्त में से एक भी परिणाम नहीं निकाला जाता है।

तो क्या होता है जब आप कमांड लाइन में सीधे कमांड टाइप करते हैं, तो एस्केप कैरेक्टर पिछले विस्तार का परिणाम नहीं होता है, इसलिए B इसे इको कमांड में भेजने से पहले हटा देता है, लेकिन दूसरे उदाहरण में, "\ *" था पिछले पैरामीटर विस्तार का परिणाम है, इसलिए इसे हटाया नहीं गया है। परिणामस्वरूप, प्रतिध्वनि "\ *" प्राप्त करती है और यही वह प्रिंट करता है।

पहले उदाहरण के बीच अंतर पर ध्यान दें - "*" उन पात्रों में शामिल नहीं है जिन्हें उद्धरण हटाने के द्वारा हटा दिया जाएगा।

मुझे लगता है कि इसका मतलब बनता है। अंत में उसी में निष्कर्ष - बस उद्धरण का उपयोग करें। मैंने सोचा था कि मैं समझाऊंगा कि बचना क्यों चाहिए, जो तार्किक रूप से काम करना चाहिए अगर केवल पैरामीटर और फाइलनेम का विस्तार खेल में हो, काम नहीं किया।

BASH विस्तार की पूरी व्याख्या के लिए, यहां देखें:

http://www.gnu.org/software/bash/manual/bashref.html#Shell-Expansions


1
बहुत बढ़िया जवाब! अब मुझे नहीं लगता कि मैंने ऐसा कोई गूंगा प्रश्न पूछा। :-)
andyuk

1
विशेष पात्रों से बचने के लिए कुछ उपयोगिता मौजूद है?
जिगर जोशी

"आपको हमेशा अजीब व्यवहार को रोकने के लिए चर को उद्धृत करना चाहिए" - जब आप उन्हें स्ट्रिंग्स के रूप में उपयोग करना चाहते हैं
एंजेलो


जबकि @finnw से ऊपर जवाब सीधे सवाल का जवाब होता है, इस सवाल का जवाब बहुत समझाने पर बेहतर है क्यों इसके बारे में, कैसे अपने स्वयं के परिदृश्यों में का उपयोग कर काम करेगा जो extrapolating में और अधिक मदद करता है। इस तरह का उत्तर हमें अधिक देखने की जरूरत है।
निकोलस

54

मैं इस पुराने सूत्र में थोड़ा जोड़ दूंगा।

आमतौर पर आप उपयोग करते होंगे

$ echo "$FOO"

हालाँकि, मुझे इस सिंटैक्स से भी समस्याएँ हैं। निम्नलिखित स्क्रिप्ट पर विचार करें।

#!/bin/bash
curl_opts="-s --noproxy * -O"
curl $curl_opts "$1"

*आवश्यकताओं के शब्दशः पारित होने के लिए curl, लेकिन एक ही समस्या आने पर होगा। उपरोक्त उदाहरण काम नहीं करेगा (यह मौजूदा निर्देशिका में फ़ाइल नाम में विस्तार करेगा) और न ही होगा \*। आप यह भी उद्धृत नहीं कर सकते $curl_optsक्योंकि इसे एकल (अमान्य) विकल्प के रूप में मान्यता दी जाएगी curl

curl: option -s --noproxy * -O: is unknown
curl: try 'curl --help' or 'curl --manual' for more information

इसलिए मैं वैश्‍विक पैटर्न पर लागू होने पर फ़ाइल नाम के विस्तार को रोकने के लिए bashचर के उपयोग की सिफारिश करूंगा $GLOBIGNOREया set -fनिर्मित ध्वज का उपयोग करूंगा ।

#!/bin/bash
GLOBIGNORE="*"
curl_opts="-s --noproxy * -O"
curl $curl_opts "$1"  ## no filename expansion

अपने मूल उदाहरण पर लागू:

me$ FOO="BAR * BAR"

me$ echo $FOO
BAR file1 file2 file3 file4 BAR

me$ set -f
me$ echo $FOO
BAR * BAR

me$ set +f
me$ GLOBIGNORE=*
me$ echo $FOO
BAR * BAR

4
महान व्याख्या, धन्यवाद! मेरा usecase है SELECT * FROM etc., यह एकमात्र तरीका है जो काम करता है।
नॉट

1
सेट-एफ समाधान पेश करने के लिए धन्यवाद!
हैचरे

5
FOO='BAR * BAR'
echo "$FOO"

यह काम करता है, लेकिन पहली पंक्ति के सिंगल कोट्स को डबल कोट्स में बदलना आवश्यक नहीं है।
14

1
नहीं, यह नहीं है, लेकिन एकल उद्धरणों का उपयोग करने की आदत बेहतर है जब आप विशेष शेल वर्णों को शामिल करने जा रहे हैं और आप कोई प्रतिस्थापन नहीं चाहते हैं।
tzot


3

यह कमांड लाइन पर printfनहीं बल्कि उपयोग करने की आदत में पड़ने लायक हो सकता है echo

इस उदाहरण में यह अधिक लाभ नहीं देता है लेकिन यह अधिक जटिल आउटपुट के साथ अधिक उपयोगी हो सकता है।

FOO="BAR * BAR"
printf %s "$FOO"

नरक में क्यों? प्रिंटफ एक अलग प्रक्रिया है (कम से कम, बिल्ट-इन-बैश नहीं) और आपके द्वारा प्रदर्शित प्रिंटफ के उपयोग से प्रतिध्वनि का कोई लाभ नहीं है।
ddaa

2
printf है एक अंतर्निहित बैश और मैं अपने जवाब "इस उदाहरण में में कहते हैं कि यह बहुत लाभ नहीं देता गए थे, लेकिन यह अधिक जटिल उत्पादन के साथ और अधिक उपयोगी हो सकता है।
डेव वेब
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.