"गूंज $ (सामान)" या "गूंज` सामान "के साथ क्या गलत है?


31

मैंने निम्नलिखित में से एक का उपयोग किया

echo $(stuff)
echo `stuff`

(जहां stuffजैसे है pwdया dateया कुछ और अधिक जटिल)।

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

लेकिन कमांड काम करता है , तो इसके साथ वास्तव में क्या गलत है?


11
यह बेमानी है और इसलिए इसका उपयोग नहीं किया जाना चाहिए। बिल्ली के बेकार उपयोग से तुलना करें: porkmail.org/era/unix/award.html
dr01

7
echo $(echo $(echo $(echo$(echo $(stuff)))))यह भी काम करता है , और अभी भी आप शायद इसका इस्तेमाल नहीं करेंगे, है ना? ;-)
पीटर -

1
आप उस विस्तार के साथ क्या करने की कोशिश कर रहे हैं, बिल्कुल?
जिज्ञासु

@curiousguy मैं अन्य उपयोगकर्ताओं की मदद करने की कोशिश कर रहा हूं, इसलिए नीचे मेरा जवाब है। हाल ही में, मैंने कम से कम तीन प्रश्न देखे हैं जो इस वाक्यविन्यास का उपयोग करते हैं। उनके लेखक ... विभिन्न करने की कोशिश कर रहे थे stuff। : डी
कामिल मैकियोरोस्की

2
इसके अलावा, क्या हम सभी इस बात से सहमत नहीं हैं कि यह एक गूंज कक्ष में खुद को सीमित करने के लिए नासमझ है ?? ;-)
पीटर - मोनिका

जवाबों:


63

tl; डॉ

एक एकमात्र सबसे शायद आपके लिए काम stuffकरेगा ।



पूरा जवाब

क्या होता है

जब आप दौड़ते हैं foo $(stuff), तो यही होता है:

  1. stuff रन;
  2. इसका आउटपुट (स्टडआउट) मुद्रित होने के बजाय, $(stuff)के मंगलाचरण में बदल जाता है foo;
  3. फिर fooचलता है, इसके कमांड लाइन तर्क स्पष्ट रूप से इस बात पर निर्भर करते हैं कि क्या stuffलौटा।

इस $(…)तंत्र को "कमांड प्रतिस्थापन" कहा जाता है। आपके मामले में मुख्य आदेश हैecho जो मूल रूप से अपने कमांड लाइन तर्कों को स्टडआउट करने के लिए प्रिंट करता है। तो जो कुछ भी stuffकरने के लिए प्रिंट करने की कोशिश करता है, उसे कैप्चर किया जाता है, पास किया जाता है echoऔर उसके द्वारा प्रिंटआउट किया जाता है echo

अगर आप का आउटपुट चाहिए stuff को प्रिंटआउट में प्रिंट किया जाए, तो केवल एकमात्र चलाएं stuff

`…`वाक्य रचना के रूप में ही उद्देश्य में कार्य करता $(…)(एक ही नाम के तहत: "कमांड प्रतिस्थापन"), वहाँ तो आप आँख बंद करके उन्हें अदला-बदली नहीं कर सकते हैं, हालांकि कुछ अंतर हैं। यह FAQ देखें और यह प्रश्न


क्या मुझे echo $(stuff)किसी भी चीज से बचना चाहिए ?

एक कारण है जिसका आप उपयोग करना चाह सकते हैं echo $(stuff)यदि आप जानते हैं कि आप क्या कर रहे हैं, तो । echo $(stuff)यदि आप वास्तव में नहीं जानते कि आपको क्या करना है, तो उसी कारण से आपको बचना चाहिए ।

बिंदु है stuffऔर echo $(stuff)बिल्कुल बराबर नहीं हैं। उत्तरार्द्ध का मतलब है stuffकि डिफॉल्ट मान के साथ आउटपुट पर स्प्लिट + ग्लोब ऑपरेटर को कॉल करना$IFS । कमांड प्रतिस्थापन का दोहराव इसे रोकता है। कमांड प्रतिस्थापन का एकल उद्धरण यह अब एक कमांड प्रतिस्थापन नहीं है।

यह देखने के लिए कि यह इन कमांड को विभाजित करने के लिए कब आता है:

echo "a       b"
echo $(echo "a       b")
echo "$(echo "a       b")"  # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "a       b")'

और ग्लोबिंग के लिए:

echo "/*"
echo $(echo "/*")
echo "$(echo "/*")"  # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "/*")'

जैसा कि आप देख सकते हैं echo "$(stuff)"समकक्ष (-ish *) से हैstuff । आप इसका उपयोग कर सकते हैं लेकिन इस तरह से चीजों को जटिल करने की क्या बात है?

दूसरी ओर यदि आप चाहते हैं कि उत्पादन stuffविभाजन + ग्लोबिंग से गुजरता है तो आप पा सकते हैंecho $(stuff) उपयोगी । हालांकि यह आपका सचेत निर्णय होना है।

आउटपुट उत्पन्न करने वाले कमांड हैं जिनका मूल्यांकन किया जाना चाहिए (जिसमें विभाजन, ग्लोबिंग और अधिक शामिल हैं) और शेल द्वारा चलाया जाता है, इसलिए eval "$(stuff)"एक संभावना है ( इस उत्तर को देखें )। मैंने कभी ऐसा कमांड नहीं देखा है जिसे मुद्रित होने से पहले अतिरिक्त विभाजन + ग्लोबिंग से गुजरने के लिए इसके आउटपुट की आवश्यकता हो । जानबूझकर उपयोग करना echo $(stuff)बहुत ही असामान्य लगता है।


व्हाट अबाउट var=$(stuff); echo "$var" ?

अच्छी बात। यह स्निपेट:

var=$(stuff)
echo "$var"

echo "$(stuff)"समतुल्य (-ish *) के बराबर होना चाहिए stuff। यदि यह पूरा कोड है, तो बस चलाएंstuff इसके बजाय ।

यदि, हालांकि, आपको stuffएक से अधिक बार इस दृष्टिकोण के आउटपुट का उपयोग करने की आवश्यकता है

var=$(stuff)
foo "$var"
bar "$var"

आमतौर पर से बेहतर है

foo "$(stuff)"
bar "$(stuff)"

यहां तक कि अगर fooहै echoऔर आप प्राप्त echo "$var"अपने कोड में, यह यह इस तरह से रखने के लिए बेहतर हो सकता है। विचार करने के लिए बातें:

  1. var=$(stuff) stuffएक बार रन के साथ ; भले ही कमांड तेज हो, एक ही आउटपुट को दो बार गणना करने से बचना सही बात है। या शायद stuffstdout को लिखने के अलावा (जैसे एक अस्थायी फ़ाइल बनाना, एक सेवा शुरू करना, एक वर्चुअल मशीन शुरू करना, एक दूरस्थ सर्वर को सूचित करना) के अलावा अन्य प्रभाव होते हैं, इसलिए आप इसे कई बार चलाना नहीं चाहते हैं।
  2. यदि आप stuffसमय-आधारित या कुछ यादृच्छिक उत्पादन उत्पन्न करते हैं, तो आपको foo "$(stuff)"और से असंगत परिणाम मिल सकते हैं bar "$(stuff)"var=$(stuff)का मान $varनिश्चित होने के बाद और आप सुनिश्चित हो सकते हैं foo "$var"और bar "$var"समान कमांड लाइन तर्क प्राप्त कर सकते हैं ।

इसके बजाय कुछ मामलों में foo "$var"आप (आवश्यकता) का उपयोग कर सकते हैं foo $var, खासकर यदि आपके stuffलिए कई तर्क उत्पन्न होते हैं foo(एक सरणी चर बेहतर हो सकता है यदि आपका शेल इसका समर्थन करता है)। फिर से जानिए कि आप क्या कर रहे हैं। यह बात आती है echoके बीच का अंतर echo $varऔर echo "$var"के बीच के समान ही है echo $(stuff)और echo "$(stuff)"


* समतुल्य ( -इश) )?

मैंने कहा कि echo "$(stuff)"(-ish) के बराबर है stuff। कम से कम दो मुद्दे हैं जो इसे बिल्कुल समकक्ष नहीं बनाते हैं:

  1. $(stuff)stuffएक उपधारा में चलाता है, इसलिए यह कहना बेहतर है कि echo "$(stuff)"(-ish) के बराबर है (-इश) (stuff)। कमांड जो शेल में चलते हैं, उन्हें प्रभावित करते हैं, यदि एक सबस्क्रिप्शन में, मुख्य शेल को प्रभावित नहीं करते हैं।

    इस उदाहरण में stuffहै a=1; echo "$a":

    a=0
    echo "$(a=1; echo "$a")"      # echo "$(stuff)"
    echo "$a"
    

    इससे तुलना कीजिए

    a=0
    a=1; echo "$a"                # stuff
    echo "$a"
    

    और साथ

    a=0
    (a=1; echo "$a")              # (stuff)
    echo "$a"
    

    एक अन्य उदाहरण के साथ शुरू stuffकिया जा रहा है cd /; pwd:

    cd /bin
    echo "$(cd /; pwd)"           # echo "$(stuff)"
    pwd
    

    और परीक्षण stuffऔर (stuff)संस्करण।

  2. echoअनियंत्रित डेटा प्रदर्शित करने के लिए एक अच्छा उपकरण नहीं है । यह echo "$var"हम बात कर रहे थे जो होना चाहिए था printf '%s\n' "$var"। लेकिन चूंकि प्रश्न का उल्लेख है echoऔर चूंकि सबसे संभावित समाधान echoपहली जगह में उपयोग नहीं करना है, इसलिए मैंने printfअब तक लागू नहीं करने का फैसला किया ।

  3. stuffया (stuff)stdout और stderr आउटपुट को इंटरलेय echo $(stuff)करेगा , जबकि stuff(जो पहले चलाता है) से सभी stderr आउटपुट प्रिंट करेगा , और उसके बाद ही stdout आउटपुट echo(जो अंतिम चलता है) पचता है ।

  4. $(…)किसी भी अनुगामी newline से स्ट्रिप्स और फिर echoइसे वापस जोड़ता है। इसलिए की echo "$(printf %s 'a')" | xxdतुलना में अलग आउटपुट देता है printf %s 'a' | xxd

  5. कुछ कमांड ( lsउदाहरण के लिए) अलग-अलग तरीके से काम करते हैं, यह निर्भर करता है कि मानक आउटपुट कंसोल है या नहीं; ऐसा ls | catनहीं lsकरता है। इसी तरह echo $(ls)से अलग तरह से काम करेगा ls

    lsएक तरफ रख दें, एक सामान्य मामले में अगर आपको इस दूसरे व्यवहार के लिए मजबूर करना है, तो इससे stuff | catबेहतर है echo $(ls)या echo "$(ls)"क्योंकि यह यहां वर्णित अन्य सभी मुद्दों को ट्रिगर नहीं करता है।

  6. संभवतः अलग-अलग निकास स्थिति (इस विकी उत्तर की पूर्णता के लिए उल्लेख किया गया है; विवरण के लिए एक और उत्तर देखें जो क्रेडिट के योग्य है)।


5
एक और अंतर: stuffरास्ता इंटरलेव stdoutऔर stderrआउटपुट echo `stuff` होगा , जबकि सभी stderrआउटपुट प्रिंट करेगा stuff, और उसके बाद ही stdoutआउटपुट।
रुस्लान

3
और यह एक और उदाहरण है: बैश स्क्रिप्ट में बहुत अधिक उद्धरण हो सकते हैं। echo $(stuff)आपको और अधिक परेशानियों में डाल सकता है जैसे echo "$(stuff)"कि आप स्पष्ट रूप से ग्लोबिंग और विस्तार नहीं चाहते हैं।
rexkogitans

2
एक और मामूली अंतर: $(…)किसी भी अनुगामी न्यूलाइन से स्ट्रिप्स और फिर echoइसे वापस जोड़ता है। इसलिए की echo "$(printf %s 'a')" | xxdतुलना में अलग आउटपुट देता है printf %s 'a' | xxd
व्युत्पन्न

1
आपको यह नहीं भूलना चाहिए कि कुछ कमांड्स ( lsउदाहरण के लिए) अलग-अलग तरीके से काम करती हैं, यह निर्भर करता है कि मानक आउटपुट कंसोल है या नहीं; ऐसा ls | catनहीं lsकरता है। और निश्चित रूप echo $(ls)से अलग से काम करेगा ls
मार्टिन रोसेनौ

@Ruslan जवाब अब सामुदायिक विकि है। मैंने आपकी उपयोगी टिप्पणी विकि पर जोड़ दी है। धन्यवाद।
कामिल मैकियोरोस्की

5

एक और अंतर: उप-शेल निकास कोड खो गया है, इसलिए echoइसके बजाय बाहर निकलने का कोड पुनर्प्राप्त किया जाता है।

> stuff() { return 1
}
> stuff; echo $?
1
> echo $(stuff); echo $?
0

3
सुपर उपयोगकर्ता में आपका स्वागत है! क्या आप उस अंतर की व्याख्या कर सकते हैं जिसे आप प्रदर्शित कर रहे हैं? धन्यवाद
bertieb

4
मेरा मानना ​​है कि इससे पता चलता है कि रिटर्न कोड एक एड के बजाय (के लिए ) का रिटर्न कोड $?होगा । समारोह (निकास कोड), लेकिन यह सेट "0" करने के लिए की वापसी कोड की परवाह किए बिना । फिर भी जवाब में होना चाहिए। echoecho $(stuff)returnstuffstuffreturn 1echostuff
इस्माइल मिगुएल

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