$ VAR बनाम $ {VAR} और बोली या नहीं उद्धृत करने के लिए


139

मैं लिख सकता हूँ

VAR=$VAR1
VAR=${VAR1}
VAR="$VAR1"
VAR="${VAR1}"

मेरे लिए अंतिम परिणाम उसी के बारे में लगता है। मुझे एक या दूसरे को क्यों लिखना चाहिए? इनमें से कोई भी पोर्टेबल / POSIX नहीं हैं?

जवाबों:


99

VAR=$VAR1का एक सरलीकृत संस्करण है VAR=${VAR1}। ऐसी चीजें हैं जो दूसरा कर सकती हैं, उदाहरण के लिए, सरणी इंडेक्स (पोर्टेबल नहीं) के संदर्भ में या सबस्ट्रिंग (POSIX-पोर्टेबल) को हटा सकती है। POSIX कल्पना में शुरुआती और पैरामीटर विस्तार के लिए बैश गाइड के चर खंड पर और देखें ।

के रूप में rm -- "$VAR1"या एक चर के आसपास उद्धरण का उपयोग करना rm -- "${VAR}"एक अच्छा विचार है। यह चर की सामग्री को एक परमाणु इकाई बनाता है। यदि चर मान में रिक्त स्थान (अच्छी तरह से, $IFSविशेष चर में वर्ण , डिफ़ॉल्ट रूप से रिक्त) या ग्लोबबिंग वर्ण हैं और आप इसे उद्धृत नहीं करते हैं, तो प्रत्येक शब्द को फ़ाइल नाम पीढ़ी (ग्लोबिंग) के लिए माना जाता है, जिसका विस्तार जो कुछ भी आप के लिए तर्क देता है 'कर रहे हैं।

$ find .
.
./*r*
./-rf
./another
./filename
./spaced filename
./another spaced filename
./another spaced filename/x
$ var='spaced filename'
# usually, 'spaced filename' would come from the output of some command and you weren't expecting it
$ rm $var
rm: cannot remove 'spaced': No such file or directory
# oops! I just ran 'rm spaced filename'
$ var='*r*'
$ rm $var
# expands to: 'rm' '-rf' '*r*' 'another spaced filename'

$ find .
.
./another
./spaced filename
./another spaced filename
$ var='another spaced filename'
$ rm -- "$var"
$ find .
.
./another
./spaced filename

पोर्टेबिलिटी पर: POSIX.1-2008 खंड 2.6.2 के अनुसार , घुंघराले ब्रेसिज़ वैकल्पिक हैं।


@ शॉन ने मेरे सवाल को अपडेट किया क्योंकि मैं पोर्टेबिलिटी के बारे में भी उत्सुक हूं
xenoterracide

@ शॉन: मुझे संदेह है कि आपका उदाहरण वैध है। क्या आपके पास शेल का कोई वास्तविक उदाहरण है जहां var1=$varविस्तार एक त्रुटि देता है?
एलेक्स

@alex: धन्यवाद। मुझे लगा कि मैंने कमांड लाइन पर परीक्षण किया है, लेकिन मैंने इसे गलत किया। मैंने उदाहरण बदल दिया।
शॉन जे। गोफ

अद्यतन उदाहरण के साथ यह ध्यान रखना बेहतर है कि आपको आमतौर पर उद्धृत संस्करण चाहिए, क्योंकि उदाहरण एक कोने का मामला है।
एलेक्स

9
@ शॉन: एक असाइनमेंट में उद्धरण आवश्यक नहीं हैं । वे सहित अधिकांश अन्य उपयोगों में आवश्यक हैं export VAR=$VAR1। ब्रेसिज़ के लिए के रूप में, वे वैकल्पिक हैं (आपके द्वारा उद्धृत अनुभाग के चौथे पैराग्राफ की जांच करें; यह सभी पूर्व-पॉसिक्स और पोसिक्स गोले में मामला है)।
गिल्स

60

${VAR}और $VARबिल्कुल बराबर हैं। एक सादे चर विस्तार के लिए, उपयोग करने का एकमात्र कारण यह है ${VAR}कि जब पार्सिंग अन्यथा चर नाम में कई वर्णों को पकड़ लेगा, जैसा कि ${VAR1}_$VAR2(जिसमें ब्रेसिज़ के बिना बराबर होगा ${VAR1_}$VAR2)। अधिकांश सजी विस्तार ( ${VAR:=default}, ${VAR#prefix}, ...) ब्रेसिज़ की आवश्यकता है।

एक चर असाइनमेंट में, फील्ड स्प्लिटिंग (यानी वैल्यू में व्हाट्सएप पर विभाजित करना) और pathname का विस्तार (यानी ग्लोबिंग) बंद हो जाता है, इसलिए सभी POSIX गोले में और सभी प्री-पॉस श में VAR=$VAR1बराबर है VAR="$VAR1"जो मैंने सुना है । (POSIX रेफ: सरल कमांड )। उसी कारण से, शाब्दिक रूप से शाब्दिक स्ट्रिंग पर VAR=*सेट VARहोता है *; निश्चित रूप से VAR=a bसेट VARकरने के लिए aके बाद से bपहली जगह में एक अलग शब्द है। सामान्य शब्दों में, दोहरे उद्धरण चिह्नों जहां खोल वाक्य रचना उदाहरण के लिए, एक शब्द भी उम्मीद अनावश्यक हैं मेंcase … in (लेकिन पैटर्न में नहीं), लेकिन फिर भी वहाँ आपको सावधान रहने की जरूरत है: उदाहरण के लिए POSIX यह बताता है किरीडायरेक्शन लक्ष्य ( >$filename) को स्क्रिप्ट्स में उद्धृत करने की आवश्यकता नहीं है, लेकिन बैश सहित कुछ गोले को स्क्रिप्ट में भी दोहरे उद्धरण चिह्नों की आवश्यकता होती है। देखें कि डबल-कोटिंग कब आवश्यक है? अधिक गहन विश्लेषण के लिए।

आपको कई मामलों में विशेष रूप से export VAR="${VAR1}"(जो कि समान रूप से लिखा जा सकता है export "VAR=${VAR1}") कई मामलों में दोहरे उद्धरण चिह्नों की आवश्यकता होती है (POSIX इस मामले को खुला छोड़ देता है)। साधारण असाइनमेंट के साथ इस मामले की समानता, और उन मामलों की सूची की बिखरी हुई प्रकृति जहां आपको दोहरे उद्धरण चिह्नों की आवश्यकता नहीं है, यही कारण है कि मैं सिर्फ दोहरे उद्धरण चिह्नों का उपयोग करने की सलाह देता हूं जब तक आप विभाजित और ग्लोब नहीं करना चाहते।


2
एक सामान्य नियम के रूप में, मैं हमेशा चर विस्तार को उद्धृत करूंगा, जब मुझे पता है कि मूल्य में कोई IFSवर्ण नहीं होगा क्योंकि मैं आदत में रहना चाहता हूं। एक अपवाद यह है कि मैं वैरिएबल असाइनमेंट करते समय मूल्य को उद्धृत नहीं करता (जब तक कि आवश्यकता न हो, जैसे कि मान में कोई स्थान होता है)। यह कमांड सिंटैक्स हाइलाइट करता है जब कमांड सब्स्टीट्यूशन जैसे कि होते हैं FOO=$(BAR=$(BAZ=blah; printf %s "${BAZ}"); printf %s "${BAR}")। सब कुछ "स्ट्रिंग" रंग में रंगने के बजाय, मुझे नेस्टेड कोड का सिंटैक्स हाइलाइटिंग मिलता है। यही कारण है कि मैं बैकटिक्स से बचता हूं।
रिचर्ड हैनसेन

जबकि >$filePOSIX लिपियों में ठीक है, तो यह और भी जब गैर-सहभागी (जब तक POSIX अनुपालन के साथ लागू की जाती है बैश में नहीं है $POSIXLY_CORRECTया --posix...)।
स्टीफन चेजलस

हालांकि यह सच है कि उद्धरणों की आवश्यकता नहीं है VAR=$VAR1, मुझे कभी-कभी आश्चर्य होता है local VAR=$VAR1, जिसे मैं कुछ मामलों में अलग-अलग तरीके से काम करना याद रखता हूं, कम से कम कुछ गोले में। लेकिन, मैं विचलन को पुन: पेश नहीं कर सकता।
संदिग्ध

ठीक है, वह मुद्दा मिला जिसे मैं याद कर रहा था । यह केवल कुछ गोले में दिखाई देता है।
संदिग्ध

@dubiousjim local VAR=$VAR1की तरह है export VAR=$VAR1, यह शेल पर निर्भर करता है।
गाइल्स

8

उद्धरण

विचार करें कि डबल-उद्धरण का उपयोग चर विस्तार के लिए किया जाता है, और एकल-उद्धरण का उपयोग मजबूत-उद्धरण के लिए किया जाता है, अर्थात, विस्तार का उपयोग।

विस्तार:

this='foo'
that='bar'
these="$this"
those='$that'

आउटपुट:

for item in "$this" "$that" "$these" "$those"; do echo "$item"; done
foo
bar
foo
$that

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

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

प्रतिस्थापन

अब यह भी विचार करें कि निर्माण "${somevar}"का उपयोग प्रतिस्थापन कार्यों के लिए किया जाता है। कई उपयोग के मामले, जैसे प्रतिस्थापन और सरणियाँ।

प्रतिस्थापन (अलग करना):

thisfile='foobar.txt.bak'
foo="${thisfile%.*}"   # removes shortest part of value in $thisfile matching after '%' from righthand side
bar="${thisfile%%.*}"  # removes longest matching

for item in "$foo" "$bar"; do echo "$item"; done
foobar.txt
foobar

प्रतिस्थापन (प्रतिस्थापन):

foobar='Simplest, least effective, least powerful'
# ${var/find/replace_with}
foo="${foobar/least/most}"   #single occurrence
bar="${foobar//least/most}"  #global occurrence (all)

for item in "$foobar" "$foo" "$bar"; do echo "$item"; done
Simplest, least effective, least powerful
Simplest, most effective, least powerful
Simplest, most effective, most powerful

सरणी:

mkdir temp
# create files foo.txt, bar.txt, foobar.txt in temp folder
touch temp/{foo,bar,foobar}.txt
# alpha is array of output from ls  
alpha=($(ls temp/*))

echo "$alpha"         #  temp/foo.txt
echo "${alpha}"       #  temp/foo.txt
echo "${alpha[@]}"    #  temp/bar.txt  temp/foobar.txt  temp/foo.txt
echo "${#alpha}"      #  12 # length of first element (implicit index [0])
echo "${#alpha[@]}"   #  3  # number of elements
echo "${alpha[1]}"    #  temp/foobar.txt # second element
echo "${#alpha[1])"   #  15 # length of second element

for item in "${alpha[@]}"; do echo "$item"; done
temp/bar.txt
temp/foobar.txt
temp/foo.txt

यह सब "${var}"घटिया निर्माण की सतह को मुश्किल से खरोंच रहा है। बैश शेल स्क्रिप्टिंग के लिए निश्चित संदर्भ ऑनलाइन संदर्भ है, टीएलडीपी द लिनक्स डॉक्यूमेंटेशन प्रोजेक्टhttps://www.tldp.org/LDP/abs/html/parameter-substitution.html


1
बहुत सूचनाप्रद।
ओरियन एल्जेनिल

0
ls -la

lrwxrwxrwx.  1 root root      31 Nov 17 13:13 prodhostname
lrwxrwxrwx.  1 root root      33 Nov 17 13:13 testhostname
lrwxrwxrwx.  1 root root      32 Nov 17 13:13 justname

फिर अंत:

env=$1
    if [ ! -f /dirname/${env}hostname ]

कर्ल का उपयोग करने के एक स्पष्ट उदाहरण के रूप में ध्यान देने योग्य है

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