क्या कोई मुझे बता सकता है कि मुझे शेल स्क्रिप्ट में चर के आसपास उद्धरण लपेटने चाहिए या नहीं?
उदाहरण के लिए, निम्नलिखित सही है:
xdg-open $URL
[ $? -eq 2 ]
या
xdg-open "$URL"
[ "$?" -eq "2" ]
और यदि हां, तो क्यों?
क्या कोई मुझे बता सकता है कि मुझे शेल स्क्रिप्ट में चर के आसपास उद्धरण लपेटने चाहिए या नहीं?
उदाहरण के लिए, निम्नलिखित सही है:
xdg-open $URL
[ $? -eq 2 ]
या
xdg-open "$URL"
[ "$?" -eq "2" ]
और यदि हां, तो क्यों?
जवाबों:
सामान्य नियम: इसे उद्धृत करें यदि यह खाली हो सकता है या इसमें रिक्त स्थान हो सकता है (या वास्तव में कोई व्हाट्सएप) या विशेष वर्ण (वाइल्डकार्ड)। रिक्त स्थान के साथ तारों को उद्धृत न करना अक्सर शेल को एक एकल तर्क को कई में तोड़ देता है।
$?
यह एक संख्यात्मक मूल्य है क्योंकि यह उद्धरण की जरूरत नहीं है। क्या $URL
जरूरत है यह इस पर निर्भर करता है कि आप वहां क्या अनुमति देते हैं और क्या आप अभी भी एक तर्क चाहते हैं यदि यह खाली है।
मैं हमेशा आदत से बाहर तार उद्धृत करते हैं क्योंकि यह इस तरह से सुरक्षित है।
IFS=0
, तो echo $?
बहुत आश्चर्य हो सकता है।
cp $source1 $source2 $dest
, लेकिन अगर के लिए कुछ अप्रत्याशित कारण dest
तैयार हो जाओ नहीं है, तीसरा तर्क बस गायब हो जाता है, और यह चुपचाप कॉपी करेंगे source1
से अधिक source2
आप एक देने के बजाय रिक्त स्थान के लिए उचित त्रुटि (जैसा कि अगर आपने प्रत्येक तर्क को उद्धृत किया होता)।
quote it if...
सोचा प्रक्रिया पीछे की ओर है - जब आप की आवश्यकता होती है तो उद्धरण कुछ ऐसा नहीं होता है, जब आप की आवश्यकता होती है तो वे कुछ ऐसे होते हैं जिन्हें आप हटा देते हैं। हमेशा सिंगल कोट्स में स्ट्रिंग्स और स्क्रिप्ट को लपेटें जब तक कि आपको दोहरे उद्धरण चिह्नों का उपयोग करने की आवश्यकता न हो (उदाहरण के लिए एक वैरिएबल का विस्तार करने के लिए) या कोई उद्धरण का उपयोग करने की आवश्यकता नहीं है (जैसे ग्लोबिंग और फ़ाइल नाम विस्तार करने के लिए)।
संक्षेप में, सब कुछ उद्धृत करें जहां आपको शेल विभाजन और वाइल्डकार्ड विस्तार करने के लिए शेल की आवश्यकता नहीं है।
एकल उद्धरण उनके बीच पाठ की रक्षा करते हैं। यह उचित उपकरण है जब आपको यह सुनिश्चित करने की आवश्यकता होती है कि शेल स्ट्रिंग को बिल्कुल भी नहीं छूता है। आमतौर पर, यह चर का विकल्प है जब आपको चर प्रक्षेप की आवश्यकता नहीं होती है।
$ 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
बहुत अधिक। लेकिन वाइल्डकार्ड मैच पर लूपिंग एक आम समस्या है, और अक्सर गलत तरीके से किया जाता है।)
एक चर जिसमें लूप ओवर या वाइल्डकार्ड का विस्तार करने के लिए टोकन की एक सूची होती है, कम बार देखा जाता है, इसलिए हम कभी-कभी "जब तक आप ठीक से नहीं जानते कि आप क्या कर रहे हैं, सब कुछ उद्धृत करते हैं"।
यहाँ सामान्य रूप से उद्धरण के लिए तीन सूत्रीय सूत्र दिया गया है:
डबल उद्धरण
संदर्भों में जहां हम शब्द विभाजन और ग्लोबिंग को दबाना चाहते हैं। इसके अलावा संदर्भों में जहां हम चाहते हैं कि शाब्दिक को एक स्ट्रिंग के रूप में माना जाए, न कि एक रेगेक्स के रूप में।
एकल कोट
स्ट्रिंग शाब्दिक में जहां हम प्रक्षेप और बैकस्लैश के विशेष उपचार को दबाना चाहते हैं। दूसरे शब्दों में, ऐसी स्थितियों में जहां दोहरे उद्धरण चिह्नों का उपयोग करना अनुचित होगा।
कोई उद्धरण नहीं
संदर्भों में जहां हम पूरी तरह से सुनिश्चित हैं कि कोई शब्द विभाजन या ग्लोबिंग मुद्दे नहीं हैं या हम शब्द विभाजन और ग्लोबिंग चाहते हैं ।
उदाहरण
डबल उद्धरण
"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"
)यह सभी देखें:
"ls" "/"
वाक्यांश "सभी स्ट्रिंग संदर्भ" को बहुत सावधानी से योग्य होने की आवश्यकता होगी।
[[ ]]
, के दाहिने हाथ की ओर =
/ ==
और =~
: यह उद्धृत करता है, यह एक पैटर्न / रेगेक्स या शाब्दिक रूप से एक स्ट्रिंग की व्याख्या करने के बीच अंतर बनाता है।
$'...'
) को निश्चित रूप से अपना स्वयं का अनुभाग होना चाहिए।
"ls" "/"
अधिक सामान्य के बजाय टाइप करना चाहिए ls /
, और मैं इसे दिशानिर्देशों में एक प्रमुख दोष के रूप में लेता हूं।
case
:)
मैं आम तौर पर "$var"
सुरक्षित के लिए उद्धृत उद्धरण का उपयोग $var
करता हूं, जब तक कि मुझे यकीन न हो कि इसमें स्थान नहीं है।
मैं $var
लाइनों में शामिल होने के लिए एक सरल तरीके के रूप में उपयोग करता हूं :
lines="`cat multi-lines-text-file.txt`"
echo "$lines" ## multiple lines
echo $lines ## all spaces (including newlines) are zapped
शेल स्क्रिप्ट में चर का उपयोग करने के लिए "" उद्धृत चर का उपयोग किया जाता है क्योंकि उद्धृत चर का मतलब है कि चर में रिक्त स्थान या विशेष वर्ण हो सकते हैं जो आपके शेल स्क्रिप्ट के निष्पादन को प्रभावित नहीं करेंगे। यदि आप अपने चर नाम में कोई स्थान या विशेष चरित्र नहीं होने के बारे में निश्चित हैं, तो आप उन्हें "" बिना उपयोग कर सकते हैं।
उदाहरण:
इको "$ url नाम" - (हर समय इस्तेमाल किया जा सकता है)
इको "$ url नाम" - (ऐसी स्थितियों में इस्तेमाल नहीं किया जा सकता है इसलिए इसे इस्तेमाल करने से पहले सावधानी बरतें)