ब्रेस विस्तार और कमांड ग्रुपिंग के बीच कैसे अंतर होता है?


47

मैंने देखा है कि {ब्रेस विस्तार में इस्तेमाल किया जा सकता है:

echo {1..8}

या कमांड ग्रुपिंग में:

{ls;echo hi}

बैश को अंतर कैसे पता चलता है?


1
बहुत बढ़िया सवाल, १। ऐसा लगता है कि यह {एक कमांड सूची के रूप में व्याख्या की जा सकती है यदि यह एक कमांड की शुरुआत में और अन्यथा ब्रेस विस्तार के रूप में प्रकट होता है, लेकिन मुझे यकीन नहीं है।
सेलाडा

16
{ls;echo hi}कानूनी नहीं है bash। समापन से पहले उद्घाटन ब्रेस और एक अर्धविराम के बाद आपको एक स्थान की आवश्यकता होती है।
पीएसकोकिक

जवाबों:


38

एक सरलीकृत कारण एक चरित्र का अस्तित्व है space:।

ब्रेस एक्सपैंशन (अन-कोटेड) स्पेस को प्रोसेस नहीं करते हैं।

एक {...}सूची की जरूरत है (संयुक्त राष्ट्र) रिक्त स्थान।

अधिक विस्तृत जवाब यह है कि शेल एक कमांड लाइन को कैसे पार करता है


कमांड लाइन को पार्स (समझने) के लिए पहला चरण इसे भागों में विभाजित करना है।
ये भाग (आमतौर पर शब्द या टोकन कहा जाता है) लिंक से प्रत्येक मेटा-चरित्र पर एक कमांड लाइन को विभाजित करने के परिणामस्वरूप होता है :

  1. मेटा-वर्णों के निश्चित सेट द्वारा अलग किए गए टोकन में कमांड को विभाजित करता है: SPACE, TAB, NEWLINE, (,), <,>, |, &, &। टोकन के प्रकारों में शब्द, कीवर्ड, I / O पुनर्निर्देशक और अर्धविराम शामिल हैं।

मेटा-वर्ण: spacetabenter;,<>|और &

विभाजन के बाद, शब्द एक प्रकार के हो सकते हैं (जैसा कि शेल द्वारा समझा जाता है):

  • आदेश पूर्व-असाइनमेंट: LC=ALL ...
  • आदेश LC=ALL echo
  • तर्क LC=ALL echo "hello"
  • पुनर्निर्देशन LC=ALL echo "hello" >&2

ब्रेस विस्तार

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

इस प्रकार, यह: {ls,-l}"ब्रेस विस्तार" के रूप में अर्हता प्राप्त करता है ls -l, या तो first wordया argument(बाश में, zsh अलग है)।

$ {ls,-l}            ### executes `ls -l`
$ echo {ls,-l}       ### prints `ls -l`

लेकिन यह नहीं होगा {ls ,-l}:। बैश spaceदो शब्दों के रूप में लाइन को विभाजित करेगा और पार्स करेगा : {lsऔर ,-l}जो ट्रिगर करेगा command not found(तर्क ,-l}खो गया है):

 $ {ls ,-l}
 bash: {ls: command not found

आपकी रेखा: दो मेटा-पात्रों और के {ls;echo hi}कारण "ब्रेस विस्तार" नहीं बनेगी ।;space

इसे इस तीन भागों में तोड़ा जाएगा: {lsनई आज्ञा echo hi}:। यह समझें कि ;एक नई कमांड की शुरुआत को ट्रिगर करता है। कमांड {lsनहीं मिलेगी, और अगला कमांड प्रिंट करेगा hi}:

$ {ls;echo hi}
bash: {ls: command not found
hi}

यदि इसे किसी अन्य कमांड के बाद रखा जाता है, तो यह वैसे भी एक नया कमांड शुरू करेगा ;:

$ echo {ls;echo hi}
{ls
hi}

सूची

"कंपाउंड कमांड" में से एक "ब्रेस लिस्ट" (मेरे शब्द) है { list; }:।
जैसा कि आप देख सकते हैं, यह रिक्त स्थान और एक समापन के साथ परिभाषित किया गया है ;
रिक्त स्थान और ;क्योंकि दोनों की जरूरत है {और }कर रहे हैं "सुरक्षित शब्द "।

और इसलिए, शब्दों के रूप में पहचाने जाने के लिए, मेटा-पात्रों (लगभग हमेशा:) से घिरा होना चाहिए space

जैसा कि लिंक किए गए पृष्ठ के बिंदु 2 में वर्णित है

  1. प्रत्येक कमांड के पहले टोकन को यह देखने के लिए चेक करता है कि क्या यह ...., {, या (, तो कमांड वास्तव में एक कंपाउंड कमांड है।

आपका उदाहरण: {ls;echo hi}सूची नहीं है।

इसे एक समापन ;और एक स्थान (कम से कम) के बाद की आवश्यकता है {। अंतिम }को समापन द्वारा परिभाषित किया गया है ;

यह एक सूची है { ls;echo hi; }। और यह { ls;echo hi;}भी है (कम आमतौर पर इस्तेमाल किया जाता है, लेकिन वैध) (मदद के लिए धन्यवाद @choroba)।

$ { ls;echo hi; }
A-list-of-files
hi

लेकिन तर्क के रूप में (शेल को अंतर पता है) कमांड के लिए, यह एक त्रुटि को ट्रिगर करता है:

$ echo { ls;echo hi; }
bash: syntax error near unexpected token `}'

लेकिन सावधान रहें कि आपको क्या विश्वास है कि शेल पार्स कर रहा है:

$ echo { ls;echo hi;
{ ls
hi

2
यह वास्तव में सबसे अच्छा जवाब है, क्योंकि आप हमें वास्तव में बश पार्सर कैसे काम करते हैं! और एक विस्तृत विवरण के साथ!
9

2
आप के बीच की जगह की जरूरत नहीं है ;और }{ ls;}अर्धविराम के रूप में काम करता है पहले से ही एक मेटा-चरित्र है।
कोरोबा

1
@lovespring धन्यवाद, हां मैंने इसे लिखने में कुछ समय लगाया। मुझे यह जानकर खुशी हुई कि यह उपयोगी है। फिर से धन्यवाद।

उत्कृष्ट लेख, संदर्भ के लिए बहुत बहुत धन्यवाद
एडवर्ड टॉर्वाल्ड्स

16

ब्लॉक {एक शेल कीवर्ड है, इसलिए इसे अगले शब्द से अंतरिक्ष से अलग होना चाहिए, जबकि ब्रेस विस्तार में, कोई स्थान नहीं होना चाहिए (यदि आपको किसी स्पेस का विस्तार करने की आवश्यकता है, तो आपको इसे बचना होगा:) echo {\ ,a}{b,c}

आप कमांड के प्रारंभ में ब्रेस विस्तार का उपयोग कर सकते हैं:

{ls,.}  # expands to "ls ."

आप इसका उपयोग किसी ब्लॉक में विस्तार करने के लिए नहीं कर सकते हैं, हालांकि, समूहीकरण कमांड के पार्सिंग विस्तार से पहले होता है:

echo {'{ ls','.;}'}  # { ls .;}
{'{ ls','.;}'}       # bash: { ls: No such file or directory

5

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

बैश में यह बहुत सरल है, क्योंकि { cmd; }इसमें रिक्त स्थान और अर्धविराम होना चाहिए। हालाँकि, उदाहरण के लिए zsh में उनकी आवश्यकता नहीं है, लेकिन फिर भी {}शेल के संदर्भ का विश्लेषण करके यह बताने में सक्षम है कि इसकी सामग्री के साथ क्या किया जाना चाहिए।

निम्नलिखित को धयान मे रखते हुए:

alias 1..3=date
{ 1..3; }    #in bash
{1..3}       #in zsh

दोनों वर्तमान तारीख को लौटते हैं, लेकिन

echo {1..3}

रिटर्न 1 2 3क्योंकि शेल {}कमांड के लिए एक तर्क में जानता है echo, इसलिए विस्तार किया जाना चाहिए।


{अनछुए स्थान के बाद बैश में ब्रेस का विस्तार शुरू नहीं होता है।
choroba

@choroba हाँ, और न केवल सही होने के बाद {। रिक्त स्थान कहीं भी नहीं हो सकता क्योंकि शेल रिक्त स्थान पर संपूर्ण कमांड लाइन को विभाजित करता है।
१०:४२ पर jijij

0

सबसे पहले, एक मिश्रित ब्रेस स्वयं और कमांड लाइन का पहला शब्द होना चाहिए:

echo { these braces are just words }

दूसरे, व्यक्तिगत ब्रेसिज़ विशेष नहीं हैं (जैसा कि आप ऊपर देख सकते हैं)। खाली ब्रेसिज़ भी विशेष नहीं हैं:

echo {} # just the token {}: familiar from the find command

अल्पविराम के बिना कुछ भी केवल स्वयं है

echo {abc} # just {abc}

यहीं से कार्रवाई शुरू होती है।

echo {a,b} # braces disappear, a b results.

तो मूल रूप से किक करने के लिए ब्रेस विस्तार के लिए, हमें एक ही शब्द (व्हॉट्सएप पर खेतों में अलग नहीं) की आवश्यकता होती है, जिसके अंदर कम से कम एक उदाहरण {...}होता है जिसके अंदर कम से कम एक अल्पविराम होता है।

यह कमांड लाइन में पहला शब्द हो सकता है, जिस तरह से:

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