शेल चर के आसपास कोट कब लपेटें?


184

क्या कोई मुझे बता सकता है कि मुझे शेल स्क्रिप्ट में चर के आसपास उद्धरण लपेटने चाहिए या नहीं?

उदाहरण के लिए, निम्नलिखित सही है:

xdg-open $URL 
[ $? -eq 2 ]

या

xdg-open "$URL"
[ "$?" -eq "2" ]

और यदि हां, तो क्यों?


2
यह भी देखें unix.stackexchange.com/questions/171346/…
tripleee

इस प्रश्न को बहुत सारे डुप्लिकेट मिलते हैं, जिनमें से कई चर के बारे में नहीं हैं, इसलिए मैं "चर" के बजाय "मूल्य" पर पहुंच गया। मुझे आशा है कि इससे और अधिक लोगों को इस विषय को खोजने में मदद मिलेगी।
त्रिकाल

1
@codeforester फिर से संपादित के साथ क्या हो रहा है?
ट्रिपलए


जवाबों:


131

सामान्य नियम: इसे उद्धृत करें यदि यह खाली हो सकता है या इसमें रिक्त स्थान हो सकता है (या वास्तव में कोई व्हाट्सएप) या विशेष वर्ण (वाइल्डकार्ड)। रिक्त स्थान के साथ तारों को उद्धृत न करना अक्सर शेल को एक एकल तर्क को कई में तोड़ देता है।

$?यह एक संख्यात्मक मूल्य है क्योंकि यह उद्धरण की जरूरत नहीं है। क्या $URLजरूरत है यह इस पर निर्भर करता है कि आप वहां क्या अनुमति देते हैं और क्या आप अभी भी एक तर्क चाहते हैं यदि यह खाली है।

मैं हमेशा आदत से बाहर तार उद्धृत करते हैं क्योंकि यह इस तरह से सुरक्षित है।


2
ध्यान दें कि "रिक्त स्थान" का वास्तव में अर्थ है "कोई भी व्हाट्सएप"।
विलियम पर्ससेल

4
@ क्रिसियन: यदि आपको यकीन नहीं है कि चर में क्या हो सकता है, तो इसे उद्धृत करना सुरक्षित है। मैं paxdiablo के रूप में एक ही सिद्धांत का पालन करते हैं, और बस सब कुछ उद्धृत करने की आदत बनाते हैं (जब तक कि कोई विशेष कारण न हो)।
गॉर्डन डेविसन

11
यदि आपको IFS का मूल्य नहीं पता है, तो बोली कि क्या कोई बात नहीं है। अगर IFS=0, तो echo $?बहुत आश्चर्य हो सकता है।
चार्ल्स डफी

3
संदर्भ के आधार पर उद्धरण, न कि आप मूल्यों के होने की उम्मीद करते हैं, अन्यथा आपके कीड़े बदतर होंगे। उदाहरण के लिए, आप सुनिश्चित करें कि आपके रास्तों में से कोई भी, रिक्त स्थान है, तो आपको लगता है कि आप लिख सकते हैं कर रहे हैं cp $source1 $source2 $dest, लेकिन अगर के लिए कुछ अप्रत्याशित कारण destतैयार हो जाओ नहीं है, तीसरा तर्क बस गायब हो जाता है, और यह चुपचाप कॉपी करेंगे source1से अधिक source2आप एक देने के बजाय रिक्त स्थान के लिए उचित त्रुटि (जैसा कि अगर आपने प्रत्येक तर्क को उद्धृत किया होता)।
डेरेक वीट

3
quote it if...सोचा प्रक्रिया पीछे की ओर है - जब आप की आवश्यकता होती है तो उद्धरण कुछ ऐसा नहीं होता है, जब आप की आवश्यकता होती है तो वे कुछ ऐसे होते हैं जिन्हें आप हटा देते हैं। हमेशा सिंगल कोट्स में स्ट्रिंग्स और स्क्रिप्ट को लपेटें जब तक कि आपको दोहरे उद्धरण चिह्नों का उपयोग करने की आवश्यकता न हो (उदाहरण के लिए एक वैरिएबल का विस्तार करने के लिए) या कोई उद्धरण का उपयोग करने की आवश्यकता नहीं है (जैसे ग्लोबिंग और फ़ाइल नाम विस्तार करने के लिए)।
एड मॉर्टन

92

संक्षेप में, सब कुछ उद्धृत करें जहां आपको शेल विभाजन और वाइल्डकार्ड विस्तार करने के लिए शेल की आवश्यकता नहीं है।

एकल उद्धरण उनके बीच पाठ की रक्षा करते हैं। यह उचित उपकरण है जब आपको यह सुनिश्चित करने की आवश्यकता होती है कि शेल स्ट्रिंग को बिल्कुल भी नहीं छूता है। आमतौर पर, यह चर का विकल्प है जब आपको चर प्रक्षेप की आवश्यकता नहीं होती है।

$ echo 'Nothing \t in here $will change'
Nothing \t in here $will change

$ grep -F '@&$*!!' file /dev/null
file:I can't get this @&$*!! quoting right.

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

$ echo "There is no place like '$HOME'"
There is no place like '/home/me'

जब आप विशेष रूप से टोकन विभाजन और / या वाइल्डकार्ड विस्तार करने के लिए शेल की आवश्यकता होती है तो कोई उद्धरण उपयुक्त नहीं है।

टोकन विभाजन;

 $ words="foo bar baz"
 $ for word in $words; do
 >   echo "$word"
 > done
 foo
 bar
 baz

इसके विपरीत:

 $ for word in "$words"; do echo "$word"; done
 foo bar baz

(लूप केवल एक बार, एकल, उद्धृत स्ट्रिंग पर चलता है।)

 $ for word in '$words'; do echo "$word"; done
 $words

(लूप केवल एक बार चलता है, शाब्दिक एकल-उद्धृत स्ट्रिंग पर।)

वाइल्डकार्ड विस्तार:

$ pattern='file*.txt'
$ ls $pattern
file1.txt      file_other.txt

इसके विपरीत:

$ ls "$pattern"
ls: cannot access file*.txt: No such file or directory

(वस्तुतः नाम की कोई फाइल नहीं है file*.txt।)

$ ls '$pattern'
ls: cannot access $pattern: No such file or directory

(कोई फ़ाइल नाम नहीं है $pattern, या तो!)

अधिक ठोस शब्दों में, फ़ाइल नाम वाले किसी भी चीज़ को आमतौर पर उद्धृत किया जाना चाहिए (क्योंकि फ़ाइल नाम में व्हॉट्सएप और अन्य शेल मेटाचैकर्स हो सकते हैं)। URL वाली कोई भी चीज़ आमतौर पर उद्धृत की जानी चाहिए (क्योंकि कई URL में शेल मेटाचैकर ?और जैसे होते हैं &)। रेगेक्स वाली कोई भी चीज आमतौर पर उद्धृत की जानी चाहिए (डिट्टो डिट्टो)। गैर-व्हॉट्सएप पात्रों के बीच एकल रिक्त स्थान के अलावा महत्वपूर्ण व्हाट्सएप वाले कुछ भी उद्धृत किए जाने की आवश्यकता है (क्योंकि अन्यथा, शेल व्हाट्सएप को प्रभावी रूप से, एकल रिक्त स्थान में बदल देगा, और किसी भी अग्रणी या अनुगामी व्हाट्सएप को ट्रिम कर देगा)।

जब आप जानते हैं कि एक चर में केवल एक मूल्य हो सकता है जिसमें कोई शेल मेटाचैकर नहीं है, तो उद्धृत करना वैकल्पिक है। इस प्रकार, एक अयोग्य $?मूल रूप से ठीक है, क्योंकि इस चर में केवल एक ही संख्या हो सकती है। हालांकि, "$?"यह भी सही है, और सामान्य स्थिरता और शुद्धता के लिए सिफारिश की जाती है (हालांकि यह मेरी व्यक्तिगत सिफारिश है, न कि व्यापक रूप से मान्यता प्राप्त नीति)।

वे मान जो वैरिएबल नहीं हैं, मूल रूप से समान नियमों का पालन करते हैं, हालांकि आप उन्हें उद्धृत करने के बजाय किसी भी मेटाचैकर से बच सकते हैं। एक सामान्य उदाहरण के लिए, इसमें मौजूद URL &को एक पृष्ठभूमि आदेश के रूप में शेल द्वारा पार्स किया जाएगा जब तक कि मेटाचैकर बच नहीं जाता या उद्धृत नहीं किया जाता है:

$ wget http://example.com/q&uack
[1] wget http://example.com/q
-bash: uack: command not found

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

wget 'http://example.com/q&uack'  # Single quotes preferred for a static string
wget "http://example.com/q&uack"  # Double quotes work here, too (no $ or ` in the value)
wget http://example.com/q\&uack   # Backslash escape
wget http://example.com/q'&'uack  # Only the metacharacter really needs quoting

अंतिम उदाहरण एक और उपयोगी अवधारणा भी सुझाता है, जिसे मैं "सीसॉ क्विंग" कहना पसंद करता हूं। यदि आपको सिंगल और डबल कोट्स को मिलाने की आवश्यकता है, तो आप उन्हें एक दूसरे से सटे उपयोग कर सकते हैं। उदाहरण के लिए, निम्नलिखित उद्धृत तार

'$HOME '
"isn't"
' where `<3'
"' is."

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

$ echo '$HOME '"isn't"' where `<3'"' is."
$HOME isn't where `<3' is.

यह भयानक रूप से सुपाठ्य नहीं है, लेकिन यह एक सामान्य तकनीक है और इस प्रकार यह जानना अच्छा है।

एक तरफ के रूप में, लिपियों को आमतौर पर किसी lsभी चीज के लिए उपयोग नहीं करना चाहिए । एक वाइल्डकार्ड का विस्तार करने के लिए, बस ... इसका उपयोग करें।

$ printf '%s\n' $pattern   # not ``ls -1 $pattern''
file1.txt
file_other.txt

$ for file in $pattern; do  # definitely, definitely not ``for file in $(ls $pattern)''
>  printf 'Found file: %s\n' "$file"
> done
Found file: file1.txt
Found file: file_other.txt

(लूप बाद के उदाहरण में पूरी तरह से printfउत्कृष्ट है ; विशेष रूप से कई तर्कों के साथ ठीक काम करता है। statबहुत अधिक। लेकिन वाइल्डकार्ड मैच पर लूपिंग एक आम समस्या है, और अक्सर गलत तरीके से किया जाता है।)

एक चर जिसमें लूप ओवर या वाइल्डकार्ड का विस्तार करने के लिए टोकन की एक सूची होती है, कम बार देखा जाता है, इसलिए हम कभी-कभी "जब तक आप ठीक से नहीं जानते कि आप क्या कर रहे हैं, सब कुछ उद्धृत करते हैं"।


1
यह एक से संबंधित प्रश्न के उत्तर के लिए (का एक हिस्सा) है । मैं इसे यहाँ पर चिपका रहा हूँ क्योंकि यह विशिष्ट है और इस विशेष समस्या के लिए विहित प्रश्न बनने के लिए पर्याप्त रूप से परिभाषित है।
ट्रिपलए

4
मैं नोट करूंगा कि यह आइटम # 0 है और mywiki.wooledge.org/BashPitfalls संग्रह पर सामान्य बैश गलतियों का पुनरावर्ती विषय है। उस सूची में कई, कई अलग-अलग आइटम मूल रूप से इस मुद्दे के बारे में हैं।
त्रिवेणी २ tri ’

27

यहाँ सामान्य रूप से उद्धरण के लिए तीन सूत्रीय सूत्र दिया गया है:

डबल उद्धरण

संदर्भों में जहां हम शब्द विभाजन और ग्लोबिंग को दबाना चाहते हैं। इसके अलावा संदर्भों में जहां हम चाहते हैं कि शाब्दिक को एक स्ट्रिंग के रूप में माना जाए, न कि एक रेगेक्स के रूप में।

एकल कोट

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

कोई उद्धरण नहीं

संदर्भों में जहां हम पूरी तरह से सुनिश्चित हैं कि कोई शब्द विभाजन या ग्लोबिंग मुद्दे नहीं हैं या हम शब्द विभाजन और ग्लोबिंग चाहते हैं


उदाहरण

डबल उद्धरण

  • सफेद स्थान के साथ शाब्दिक तार ( "StackOverflow rocks!", "Steve's Apple")
  • चर विस्तार ( "$var", "${arr[@]}")
  • आदेश प्रतिस्थापन ( "$(ls)", "`ls`")
  • ग्लब्स जहां निर्देशिका पथ या फ़ाइल नाम भाग में रिक्त स्थान शामिल हैं ( "/my dir/"*)
  • एकल उद्धरण की रक्षा के लिए ( "single'quote'delimited'string")
  • बैश पैरामीटर विस्तार ( "${filename##*/}")

एकल कोट

  • कमांड के नाम और तर्क जिसमें उनमें व्हाट्सएप है
  • शाब्दिक तार जिसे दबाने के लिए प्रक्षेप की आवश्यकता होती है ( 'Really costs $$!', 'just a backslash followed by a t: \t')
  • दोहरे उद्धरण चिह्नों की सुरक्षा के लिए ( 'The "crux"')
  • रेगेक्स शाब्दिक जिन्हें दबाने के लिए प्रक्षेप की आवश्यकता होती है
  • विशेष वर्णों को शामिल करने वाले शाब्दिकों के लिए शेल का उपयोग करें ( $'\n\t')
  • शेल का उपयोग करें जहाँ हमें कई सिंगल और डबल कोट्स ( $'{"table": "users", "where": "first_name"=\'Steve\'}') की सुरक्षा करने की आवश्यकता है

कोई उद्धरण नहीं

  • चारों ओर मानक अंक चर ( $$, $?, $#आदि)
  • अंकगणितीय संदर्भों में ((count++)), जैसे "${arr[idx]}","${string:start:length}"
  • अंदर की [[ ]]अभिव्यक्ति जो शब्द विभाजन और ग्लोबिंग मुद्दों से मुक्त है (यह शैली का मामला है और राय व्यापक रूप से भिन्न हो सकती है)
  • जहाँ हम शब्द विभाजन चाहते हैं ( for word in $words)
  • जहां हम ग्लोबिंग ( for txtfile in *.txt; do ...) चाहते हैं
  • जहाँ हम ~व्याख्या करना चाहते हैं $HOME( ~/"some dir"लेकिन नहीं "~/some dir")

यह सभी देखें:


3
इन दिशानिर्देशों के अनुसार, किसी को रूट डायरेक्टरी में फाइलों की एक सूची मिलेगी, जिसमें "ls" "/" वाक्यांश "सभी स्ट्रिंग संदर्भ" को बहुत सावधानी से योग्य होने की आवश्यकता होगी।
विलियम पर्ससेल

5
में [[ ]], के दाहिने हाथ की ओर =/ ==और =~: यह उद्धृत करता है, यह एक पैटर्न / रेगेक्स या शाब्दिक रूप से एक स्ट्रिंग की व्याख्या करने के बीच अंतर बनाता है।
बेंजामिन डब्ल्यू।

6
एक अच्छा अवलोकन, लेकिन @ बेंजामिन डब्ल्यू की टिप्पणियां एकीकृत करने के लायक हैं और एएनएसआई सी-उद्धृत स्ट्रिंग्स ( $'...') को निश्चित रूप से अपना स्वयं का अनुभाग होना चाहिए।
mklement0

3
@ mklement0, वास्तव में वे समकक्ष हैं। इन दिशानिर्देशों से संकेत मिलता है कि आपको हमेशा "ls" "/"अधिक सामान्य के बजाय टाइप करना चाहिए ls /, और मैं इसे दिशानिर्देशों में एक प्रमुख दोष के रूप में लेता हूं।
विलियम पुरसेल

4
के लिए कोई उद्धरण आप चर काम या जोड़ सकते हैं case:)
PesaThe

4

मैं आम तौर पर "$var"सुरक्षित के लिए उद्धृत उद्धरण का उपयोग $varकरता हूं, जब तक कि मुझे यकीन न हो कि इसमें स्थान नहीं है।

मैं $varलाइनों में शामिल होने के लिए एक सरल तरीके के रूप में उपयोग करता हूं :

lines="`cat multi-lines-text-file.txt`"
echo "$lines"                             ## multiple lines
echo $lines                               ## all spaces (including newlines) are zapped

अंतिम टिप्पणी कुछ भ्रामक है; newlines प्रभावी रूप से रिक्त स्थान के साथ बदल दिए जाते हैं, बस हटाए नहीं जाते।
ट्रिपलए

-1

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

उदाहरण:

इको "$ url नाम" - (हर समय इस्तेमाल किया जा सकता है)

इको "$ url नाम" - (ऐसी स्थितियों में इस्तेमाल नहीं किया जा सकता है इसलिए इसे इस्तेमाल करने से पहले सावधानी बरतें)

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