शेल स्क्रिप्ट में बैकटिक्स के बजाय $ () का उपयोग करने का क्या लाभ है?


175

कमांड लाइन के आउटपुट को कैप्चर करने के दो तरीके हैं bash:

  1. लिगेसी बॉर्न शेल बैकिक्स ``:

    var=`command`
  2. $() वाक्यविन्यास (जो मुझे अब तक पता है कि बैश विशिष्ट है, या कम से कम गैर-पॉसिक्स पुराने गोले जैसे कि 1 बॉरो द्वारा समर्थित नहीं है)

    var=$(command)

क्या बैकटिक्स की तुलना में दूसरे सिंटैक्स का उपयोग करने का कोई लाभ है? या दो पूरी तरह से 100% समकक्ष हैं?


14
$()POSIX है और सभी आधुनिक बॉर्न शेल द्वारा समर्थित है, जैसे ksh, bash, ash, dash, zsh, busybox, आप इसे नाम देते हैं। (ऐसा नहीं है कि एक आधुनिक सोलारिस है /bin/sh, लेकिन सोलारिस पर आप /usr/xpg4/bin/shइसके बजाय आधुनिक का उपयोग करना सुनिश्चित करेंगे )।
जेन्स

27
इसके अलावा, $()उपनाम और उपनामों के बारे में एक नोट । यदि आपके पास alias foo=$(command)है .bashrcतो तब commandनिष्पादित किया जाएगा जब .bashrcव्याख्या के दौरान उर्फ ​​कमांड स्वयं चलाया जाता है। साथ alias foo=`command`, commandहर बार उर्फ चलाया जाता है निष्पादित किया जाएगा। लेकिन अगर आप से बचने के $साथ $()प्रपत्र (जैसे alias foo=\$(command)), यह भी हर बार उर्फ चलाया जाता है के बजाय दौरान निष्पादित करेंगे, .bashrcव्याख्या। जहाँ तक मैं परीक्षण करके बता सकता हूँ, वैसे भी; मुझे बैश डॉक्स में कुछ भी नहीं मिला, जो इस व्यवहार की व्याख्या करते हैं।
dirtside

4
@dirtside यह कौन सा शेल है, मैंने bash और POSIX शेल का परीक्षण किया है, जब मैं स्रोत करता हूं तो बैकटिक निष्पादित होता है। सरल उदाहरण: उर्फ ​​क्यूरेट = `तारीख` के बाद मैंने इसे स्रोत और क्यूरेट चलाया, तो मुझे संदेश मिला कि यह कमांड सोम (सोमवार को मिला) नहीं मिल सकता है, उदाहरण के लिए।
हवाई

@dirtside यह सच नहीं है। उर्फ फू के साथ भी = `command` commandकेवल एक बार ही निष्पादित किया जाता है। मैंने इसे चेक किया: फंक्शन आआ () {प्रिंटफ डेट; गूंज आ गया >> ~ / test.txt; } उपनाम परीक्षण 1 = aaa। फ़ंक्शन आआ केवल एक बार (प्रत्येक लॉगिन के बाद test1) निष्पादित कर रहा है, चाहे कितनी बार उर्फ ​​( ) निष्पादित किया गया हो। मैंने .bashrc (डेबियन 10 पर) का उपयोग किया।
महत्वपूर्णदेव

कोई विचार नहीं, यह साढ़े पांच साल पहले बाश का जो भी संस्करण था, वह उस बिंदु से भी बहुत पुराना था। यह संभव है कि मेरा परीक्षण गलत था, लेकिन यह अब शायद ही मायने रखता है क्योंकि मुझे संदेह है कि कोई भी अभी भी जो भी संस्करण का उपयोग कर रहा है।
dirtside

जवाबों:


156

प्रमुख एक उन्हें घोंसला बनाने की क्षमता है , आज्ञाओं के भीतर आदेश, आपकी पवित्रता को खोने के बिना यह पता लगाने की कोशिश कर रहा है कि भागने का कुछ रूप बैकटीक्स पर काम करेगा।

एक उदाहरण, हालांकि कुछ हद तक वंचित:

deps=$(find /dir -name $(ls -1tr 201112[0-9][0-9]*.txt | tail -1l) -print)

जो आपको /dirडायरेक्टरी ट्री में सभी फाइलों की एक सूची देगा, जिनका नाम दिसंबर 2011 (क) से सबसे पहले दिनांकित पाठ फ़ाइल के समान है ।

एक और उदाहरण कुछ ऐसा होगा जैसे कि मूल निर्देशिका का नाम (पूर्ण पथ नहीं) प्राप्त करना:

pax> cd /home/pax/xyzzy/plugh
pax> parent=$(basename $(dirname $PWD))
pax> echo $parent
xyzzy

(ए) अब वह विशिष्ट कमांड वास्तव में काम नहीं कर सकता है, मैंने कार्यक्षमता का परीक्षण नहीं किया है। इसलिए, यदि आप मुझे इसके लिए वोट देते हैं, तो आप इरादे से चूक गए हैं :-) यह सिर्फ एक दृष्टांत के रूप में है कि आप कैसे घोंसला बना सकते हैं, बग-रहित उत्पादन के लिए तैयार स्निपेट के रूप में नहीं।


87
मैं उम्मीद करता हूं कि एसओ पर सभी कोड उत्पादन के लिए तैयार स्निपेट होंगे, जिन्हें नासा शटल कोड विश्वसनीयता मानकों के लिए तैयार किया गया है। कुछ भी कम हो जाता है एक झंडा और एक वोट हटा दें।
DVK

1
@Dvk यदि आप मजाक नहीं कर रहे हैं, तो मैं असहमत हूं कि कोड वार को ऐसे वारंटियों या उद्देश्य की फिटनेस की अनुमति देने के लिए SO डिफॉल्ट्स (CC-BY-SA या MIT लाइसेंस) से स्वचालित रूप से दूर रहने में विफल रहने के लिए ध्वजांकित किया जाना चाहिए। इसके बजाय मैं अपने जोखिम पर एसओ पर कोड का पुन: उपयोग करूंगा, और मदद के हिसाब से वोट का योगदान, तकनीकी योग्यता, आदि
chrstphrchvz

9
@chrstphrchvz, यदि आप मेरी प्रोफ़ाइल को देखते हैं, तो आपको यह छोटा सा स्निपेट दिखाई देगा: "स्टैक ओवरफ़्लो पर मैं जो भी कोड पोस्ट करता हूं, उसे" लाइसेंस के साथ जो भी करना चाहते हैं, "लाइसेंस द्वारा कवर किया जाता है, जिसका पूरा पाठ: Do whatever the heck you want with it." :-) किसी भी मामले में, मुझे बहुत यकीन है कि यह DVK से हास्य था।
paxdiablo

1
लेकिन क्या हुआ अगर यह "सीडी / होम / पैक्स / xyzzy / प्लोवर" था? क्या आप अपने आप को अलग-अलग छोटे-छोटे मार्गों के चक्रव्यूह में पा सकते हैं?
डंकन

@wchargin क्या आप जानते हैं कि यह घटना C ++ भाषा में प्रयुक्त परिभाषित शाब्दिक अर्थों को जोड़ने के लिए एक प्राथमिक प्रेरक थी? en.cppreference.com/w/cpp/language/user_literal
थॉमसमैकल

59

मान लीजिए कि आप जहां gccस्थापित है, उसी के अनुसार लिबर डायरेक्टरी ढूंढना चाहते हैं । आपके पास विकल्प है:

libdir=$(dirname $(dirname $(which gcc)))/lib

libdir=`dirname \`dirname \\\`which gcc\\\`\``/lib

पहला दूसरे की तुलना में आसान है - पहले का उपयोग करें।


4
उन कमांड प्रतिस्थापन के आसपास कुछ उद्धरण देखना अच्छा होगा!
टॉम फेनेच

1
कम से कम बैश के लिए, @TomFenech की टिप्पणी असाइनमेंट्स पर लागू नहीं होती है। x=$(f); x=`f` जैसा व्यवहार करें x="$(f)"; x="`f`"। इसके विपरीत, सरणी असाइनमेंट वर्णों में बंटवारे का प्रदर्शन x=($(f)); x=(`f`) करते हैं, $IFSजब आदेशों को लागू करना अपेक्षित होता है। यह सुविधाजनक है ( x=1 2 3 4समझ में नहीं आता) लेकिन असंगत है।
kdb

@kdb आप x=$(f)बिना उद्धरणों के काम करने के बारे में सही हैं । मुझे और अधिक विशिष्ट होना चाहिए था; मैं उपयोग करने का प्रस्ताव कर रहा था libdir=$(dirname "$(dirname "$(which gcc)")")/lib( आंतरिक कमांड प्रतिस्थापन के आसपास के उद्धरण )। यदि अयोग्य घोषित कर दिया गया है, तो आप अभी भी सामान्य शब्द विभाजन और ग्लोब विस्तार के अधीन हैं।
टॉम फेनेच

38

बैकटिक्स ( `...`) गैर-पोसिक्स-संगत बॉर्न-शेल के केवल सबसे पुराने द्वारा आवश्यक विरासत सिंटैक्स $(...)है और कई कारणों से पोसिक्स और अधिक पसंदीदा है:

  • बैकस्लैक्स ( \बैकस्टिक्स के अंदर) को गैर-स्पष्ट तरीके से नियंत्रित किया जाता है:

    $ echo "`echo \\a`" "$(echo \\a)"
    a \a
    $ echo "`echo \\\\a`" "$(echo \\\\a)"
    \a \\a
    # Note that this is true for *single quotes* too!
    $ foo=`echo '\\'`; bar=$(echo '\\'); echo "foo is $foo, bar is $bar" 
    foo is \, bar is \\
  • अंदर उद्धृत नेस्टिंग $()कहीं अधिक सुविधाजनक है:

    echo "x is $(sed ... <<<"$y")"

    के बजाय:

    echo "x is `sed ... <<<\"$y\"`"

    या कुछ लिखना:

    IPs_inna_string=`awk "/\`cat /etc/myname\`/"'{print $1}' /etc/hosts`

    क्योंकि $()उद्धृत करने के लिए एक पूरी तरह से नए संदर्भ का उपयोग करता है

    जो बोर्न और कोर्न गोले के रूप में पोर्टेबल नहीं है, उन्हें इन बैकस्लैश की आवश्यकता होगी, जबकि बैश और डैश नहीं।

  • नेस्टिंग कमांड प्रतिस्थापन के लिए सिंटैक्स आसान है:

    x=$(grep "$(dirname "$path")" file)

    से:

    x=`grep "\`dirname \"$path\"\`" file`

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

    कुछ और उदाहरण:

    echo `echo `ls``      # INCORRECT
    echo `echo \`ls\``    # CORRECT
    echo $(echo $(ls))    # CORRECT
  • यह backquotes का उपयोग करते समय असंगत व्यवहार की समस्या को हल करता है:

    • echo '\$x' आउटपुट \$x
    • echo `echo '\$x'` आउटपुट $x
    • echo $(echo '\$x') आउटपुट \$x
  • बैकटिक्स सिंटैक्स में एम्बेडेड कमांड की सामग्री पर ऐतिहासिक प्रतिबंध हैं और कुछ मान्य स्क्रिप्ट को संभाल नहीं सकते हैं, जिसमें बैकक्वाटर शामिल हैं, जबकि नया $()रूप किसी भी प्रकार की वैध एम्बेडेड स्क्रिप्ट को संसाधित कर सकता है।

    उदाहरण के लिए, ये अन्यथा मान्य एम्बेडेड स्क्रिप्ट बाएं कॉलम में काम नहीं करते हैं, लेकिन दाईं ओर IEEE पर काम करते हैं :

    echo `                         echo $(
    cat <<\eof                     cat <<\eof
    a here-doc with `              a here-doc with )
    eof                            eof
    `                              )
    
    
    echo `                         echo $(
    echo abc # a comment with `    echo abc # a comment with )
    `                              )
    
    
    echo `                         echo $(
    echo '`'                       echo ')'
    `                              )

इसलिए $-प्रोटेक्टेड कमांड प्रतिस्थापन के लिए वाक्यविन्यास पसंदीदा तरीका होना चाहिए, क्योंकि यह साफ वाक्यविन्यास (मानव और मशीन की पठनीयता में सुधार) के साथ स्पष्ट रूप से स्पष्ट है, यह घोंसला बनाने योग्य और सहज है, इसका आंतरिक पार्सिंग अलग है, और यह अधिक सुसंगत भी है (साथ अन्य सभी विस्तार जो दोहरे कोट्स के भीतर से पार्स किए गए हैं) जहां बैकटिक्स एकमात्र अपवाद हैं और `चरित्र आसानी से छला जाता है जब "इसे पढ़ने के लिए और भी मुश्किल बना दिया जाता है, खासकर छोटे या असामान्य फोंट के साथ।

स्रोत: (बैकटिक्स) को क्यों $(...)पसंद किया जाता है `...`? BashFAQ पर

यह सभी देखें:


1
एक्सेंट ग्रेविस-शैली प्रतिस्थापन में नेस्टेड उद्धरण वास्तव में अपरिभाषित है, आप दोहरे उद्धरण चिह्नों का उपयोग या तो बाहर या अंदर नहीं कर सकते हैं , लेकिन दोनों, आंशिक रूप से। गोले उन्हें अलग तरह से व्याख्या करते हैं; कुछ को बचने के लिए बैकस्लैश की आवश्यकता होती है, कुछ की आवश्यकता होती है कि वे बैकस्लैश-बच न जाएं।
22 अक्टूबर को mirabilos

23

मैन बैश से:

          $(command)
   or
          `command`

   Bash performs the expansion by executing command and replacing the com-
   mand  substitution  with  the  standard output of the command, with any
   trailing newlines deleted.  Embedded newlines are not deleted, but they
   may  be  removed during word splitting.  The command substitution $(cat
   file) can be replaced by the equivalent but faster $(< file).

   When the old-style backquote form of substitution  is  used,  backslash
   retains  its  literal  meaning except when followed by $, `, or \.  The
   first backquote not preceded by a backslash terminates the command sub-
   stitution.   When using the $(command) form, all characters between the
   parentheses make up the command; none are treated specially.

9

अन्य उत्तरों के अलावा,

$(...)

की तुलना में नेत्रहीन बेहतर है

`...`

बैकस्टिक्स एपोस्ट्रोफ्स की तरह बहुत अधिक दिखते हैं; यह आपके द्वारा उपयोग किए जा रहे फ़ॉन्ट के आधार पर भिन्न होता है।

(और, जैसा कि मैंने अभी देखा, इनलाइन कोड के नमूने दर्ज करने के लिए बैकटिक्स बहुत कठिन हैं।)


2
आपके पास एक अजीब कीबोर्ड होना चाहिए (या मैं करता हूं?)। मेरे लिए, बैकटिक्स टाइप करना बहुत आसान है - वे शीर्ष बाएं कोने की कुंजी हैं, कोई SHIFT या ALT आवश्यक नहीं है।
DVK

1
@ डीवीडीके: मैं उनकी उपस्थिति के बारे में बात कर रहा था, टाइपिंग में आसानी नहीं। (मेरे कुंजीपटल शायद तुम्हारा के समान है।) फिर भी, अब है कि आप इसे का उल्लेख है, मुझे लगता है कि मैं के लिए बेहतर मांसपेशी स्मृति $ (और )मैं बैकटिक के लिए की तुलना में; YMMV।
कीथ थॉम्पसन

कभी भी बैश में प्रोग्राम नहीं किया (पुराने ksh से पर्ल तक फिसल गया) तो निश्चित रूप से उस विशिष्ट वाक्यविन्यास के लिए कोई स्मृति नहीं है :)
DVK

1
@ डीवीडीके, मुझे लगा कि कीथ इस तथ्य का उल्लेख कर रहे हैं कि गैर-ब्लॉक कोड यहां (ब्लॉक कोड का अर्थ है लाइन के शुरू में चार रिक्त स्थान का उपयोग करना) यह इंगित करने के लिए बैकटिक्स का उपयोग करता है, जिससे बैकटीक्स को डालना मुश्किल हो जाता है, एक और चित्रण नेस्टिंग कठिनाइयों :-) FWIW, आप कोड और / कोड टैग (गैर-ब्लॉक कोड करने का दूसरा तरीका) पा सकते हैं और अधिक आसानी से backticks शामिल कर सकते हैं।
paxdiablo

@ पैक्स - मिल गया। ओह! मैं वास्तव में किसी कारण से मानसिक रूप से ब्लॉककोड पर अटक गया था।
DVK

7

$() घोंसले के शिकार की अनुमति देता है।

out=$(echo today is $(date))

मुझे लगता है कि बैकटिक्स इसकी अनुमति नहीं देता है।


2
आप बैकटिक्स घोंसला कर सकते हैं; यह बहुत कठिन है out=`echo today is \`date\`` :।
जोनाथन लेफलर

4

यह POSIX मानक है जो $(command)कमांड प्रतिस्थापन के रूप को परिभाषित करता है । आज उपयोग किए जाने वाले अधिकांश गोले पोसिक्स के अनुरूप हैं और पुरातन बैकटिक नोटेशन पर इस पसंदीदा रूप का समर्थन करते हैं। शेल भाषा दस्तावेज़ का कमांड प्रतिस्थापन अनुभाग (2.6.3) इसका वर्णन करता है:

कमांड प्रतिस्थापन एक कमांड के आउटपुट को कमांड नाम के स्थान पर प्रतिस्थापित करने की अनुमति देता है। कमांड प्रतिस्थापन तब होता है जब कमांड निम्नानुसार संलग्न है:

$(command)

या (backquoted संस्करण):

`command`

खोल क्रियान्वित करते हुए आदेश प्रतिस्थापन का विस्तार करेगा आदेश एक subshell वातावरण में (देखें शैल निष्पादन पर्यावरण और आदेश प्रतिस्थापन (के पाठ की जगह) आदेश आदेश के मानक उत्पादन के साथ साथ साथ संलग्न "$ ()" या backquotes), को हटाने <newline>प्रतिस्थापन के अंत में एक या एक से अधिक वर्णों का क्रम । <newline>आउटपुट के अंत से पहले एंबेडेड वर्णों को हटाया नहीं जाएगा; हालाँकि, उन्हें क्षेत्र के सीमांकक के रूप में माना जा सकता है और क्षेत्र विभाजन के दौरान समाप्त किया जा सकता है, जो कि IFS के मूल्य पर निर्भर करता है और जो प्रभाव में है। यदि आउटपुट में कोई नल बाइट्स है, तो व्यवहार अनिर्दिष्ट है।

आदेश प्रतिस्थापन के पीछे की शैली के भीतर, <backslash>इसके शाब्दिक अर्थ को बनाए रखेगा, इसके बाद जब: ' $', ' `', या <backslash>। मिलान किए गए बैककौट की खोज पहले गैर-बच गए बैककौट से संतुष्ट होगी; इस खोज के दौरान, यदि एक गैर-बच गए बैककॉट का शेल टिप्पणी के भीतर सामना किया जाता है, तो यहां एक दस्तावेज, $ ( कमांड ) फॉर्म का एक एम्बेडेड कमांड प्रतिस्थापन , या एक उद्धृत स्ट्रिंग, अपरिभाषित परिणाम होते हैं। एक एकल-उद्धृत या डबल-उद्धृत स्ट्रिंग जो शुरू होता है, लेकिन समाप्त नहीं होता है, " `...`" अनुक्रम के भीतर अपरिभाषित परिणाम पैदा करता है।

$ ( कमांड ) फॉर्म के साथ, ओपन कोष्ठक के मिलान समापन कोष्ठक के बाद सभी वर्ण कमांड का गठन करते हैं । किसी भी मान्य शेल स्क्रिप्ट का उपयोग कमांड के लिए किया जा सकता है , केवल एक स्क्रिप्ट को छोड़कर जिसमें अप्रत्यक्ष परिणाम होते हैं।

आदेश प्रतिस्थापन के परिणामों को आगे के टिल्ड विस्तार, पैरामीटर विस्तार, कमांड प्रतिस्थापन या अंकगणितीय विस्तार के लिए संसाधित नहीं किया जाएगा। यदि कोई कमांड प्रतिस्थापन डबल-कोट्स के अंदर होता है, तो प्रतिस्थापन के परिणाम पर फ़ील्ड विभाजन और पाथनेम विस्तार नहीं किया जाएगा।

कमांड प्रतिस्थापन को नस्ट किया जा सकता है। बैककोट संस्करण के भीतर घोंसले के शिकार को निर्दिष्ट करने के लिए, आवेदन <backslash>पात्रों के साथ आंतरिक बैकक्वाटर से पहले होगा ; उदाहरण के लिए:

\`command\`

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

$( (command) )


4

यह एक विरासत सवाल है, लेकिन मैं की एक पूरी तरह से वैध उदाहरण के साथ आया था $(...)से अधिक `...`

मैं एक रिमोट डेस्कटॉप का उपयोग करके विंडोज़ चला रहा था, जो कि साइबरगैन चला रहा था और एक कमांड के परिणामस्वरूप इसे पुनरावृत्त करना चाहता था। अफसोस की बात यह है कि बैकटिक कैरेक्टर में प्रवेश करना असंभव था, या तो रिमोट डेस्कटॉप चीज या साइबरविन के कारण।

यह मान लेना समझ से बाहर है कि एक डॉलर चिह्न और कोष्ठक इस तरह के अजीब सेटअपों में टाइप करना आसान होगा।

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