पाइप की वरीयता (|) और तार्किक और (&&) बैश में


17

ऑपरेटर वरीयता के साथ क्लासिक परिदृश्य, आपके पास एक पंक्ति है जैसे:

(cd ~/screenshots/ && ls screenshot* | head -n 5)

और आप नहीं जानते कि यह पार्स है ((A && B) | C)या (A && B | C)...

लगभग आधिकारिक दस्तावेज पाया यहाँ सूची में पाइप की सूची नहीं है तो मैं बस तालिका में जांच नहीं कर सकता।

इसके अलावा बाश में, (न केवल संचालन के क्रम को बदलने के लिए है, बल्कि एक उपखंड बनाता है , इसलिए मुझे 100% यकीन नहीं है कि यह लाइनें पिछली पंक्ति के बराबर है:

((cd ~/screenshots/ && ls screenshot*) | head -n 5)

आम तौर पर, कैसे एक बैश लाइन का एएसटी पता करने के लिए ? अजगर में मेरा एक कार्य है जो मुझे पेड़ देता है ताकि मैं ऑपरेशन के क्रम को आसानी से जांच सकूं।


1
यह जानने में मदद मिल सकती है कि |सिर्फ एक कनेक्टर है जो आरएचएस स्टड के लिए एलएचएस स्टैडआउट को फिट करता है। तो अगर cdआपके उदाहरण में कमांड विफल रहता है, तो यह कोई आउटपुट नहीं भेजेगा head, लेकिन headवास्तव में अभी भी execute, कुछ भी नहीं, और कोई आउटपुट नहीं लौटाएगा।
डोपघोटी


1
bashएक याक पार्सर का उपयोग कर रहा है कुछ तदर्थ बात नहीं है; यदि आप yacc -vइसे चलाते हैं, तो यह आपको y.outputएक अच्छे व्याकरण में देगा, जो दिखाता है कि &&और ||सूचियों को संयोजित करता है, और सूचियाँ अंततः पाइपलाइनों से बनी होती हैं (और रिवर्स नहीं); tl; डॉ; अपेक्षा के अनुरूप A && B | Cही A && { B | C; }है। Bऔर के बीच निष्पादन के किसी भी आदेश को न मानें C; एक पाइपलाइन में कमांड समानांतर में चलाए जाते हैं
मॉसवी

1
ध्यान दें कि "लगभग आधिकारिक दस्तावेज" जो आपको इंगित करता है, पूरी तरह से अप्रासंगिक है, क्योंकि यह [...]परीक्षण और $((...))अंकगणितीय मूल्यांकन के अंदर उपयोग किए जाने वाले ऑपरेटरों के बारे में है ; विशेष रूप से, ||और &&जैसा कि शेल भाषा में कमांड सूची के साथ उपयोग किया जाता है , संबंधित संचालकों के विपरीत Cया अंकगणितीय मूल्यांकन (जहां &&अधिक कसकर बांधता है ||) के विपरीत एक ही पूर्वता है
मॉसवी

@mosvy, दस्तावेज़ यह भी नहीं कहता कि तालिका किस संदर्भ में लागू होती है, इसलिए यह उस अर्थ में भी उपयोगी से कम लगती है ...
ilkkachu

जवाबों:


21
cd ~/screenshots/ && ls screenshot* | head -n 5

इसके बराबर है

cd ~/screenshots && { ls screenshot* | head -n 5 ; }

( ब्रेसिज़ समूह बिना सबस्क्रिप्शन के एक साथ कमांड करता है )। इस |प्रकार की उच्चता ( &&और अधिक सख्त होती है) की तुलना में और ||। अर्थात्,

A && B | C

तथा

A || B | C

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

{ A && B ; } | C
A && { B | C ; } # This is the default, but you might sometimes want to be explicit

आप कुछ अलग कमांड का उपयोग करके इसका परीक्षण कर सकते हैं। अगर तुम दौड़ते हो

echo hello && echo world | tr a-z A-Z

तो आपको मिलेगा

hello
WORLD

वापस: tr a-z A-Zऊपरी-मामलों में इसका इनपुट , और आप देख सकते हैं कि केवल echo worldइसमें पाइप किया गया था, जबकि echo helloअपने आप ही गुजरता था।


यह है के रूप में परिभाषित खोल व्याकरण : है, हालांकि नहीं बहुत स्पष्ट रूप से and_or(के लिए उत्पादन &&/ ||) आ करने के लिए परिभाषित किया गया है pipeline, उसके शरीर में जबकि pipelineबस में शामिल है command, जो नहीं करता है को शामिल and_or- केवल complete_commandउत्पादन तक पहुँच सकते हैं and_or, और यह केवल पर मौजूद है शीर्ष स्तर और कार्यों और छोरों जैसे संरचनात्मक निर्माण के निकायों के अंदर।

आप मैन्युअल रूप से उस व्याकरण को एक कमांड के लिए पार्स ट्री प्राप्त करने के लिए आवेदन कर सकते हैं, लेकिन बैश स्वयं कुछ भी प्रदान नहीं करता है। मैं किसी ऐसे शेल के बारे में नहीं जानता जो अपने स्वयं के पार्सिंग के लिए उपयोग किए जाने से परे है।

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

बाहरी पार्सर हैं जो सिंटैक्स से मेल खाने और एक पेड़ का निर्माण करने का प्रयास करते हैं, और उनमें से मैं मोटे तौर पर मोरबीग की सिफारिश करूंगा , जो सबसे विश्वसनीय होने का प्रयास करता है।


7

टीएल; डीआर : सूची विभाजक जैसे ;&, &&और ||पार्सिंग ऑर्डर तय करें।

बैश मैनुअल हमें बताता है:

AND और OR सूची एक और अधिक पाइपलाइनों के अनुक्रम हैं जिन्हें && और || क्रमशः नियंत्रण संचालक।

या कैसे बैश हैकर की विकी ने सफलतापूर्वक इसे डाल दिया

<PIPELINE1> && <PIPELINE2>

इस प्रकार, cd ~/screenshots/ && ls screenshot* | head -n 5 एक पाइपलाइन है - ls screenshot* | head -n 5और एक साधारण कमांड cd ~/screenshots/। ध्यान दें कि मैनुअल के अनुसार

एक पाइप लाइन में प्रत्येक कमांड को एक अलग प्रक्रिया के रूप में निष्पादित किया जाता है (यानी, एक सबहेल में)।

दूसरी ओर, (cd ~/screenshots/ && ls screenshot*) | head -n 5अलग है - आपके पास एक पाइप लाइन है: बाईं ओर उपधारा है और आपके पास दाईं ओर है head -n 5। इस मामले में, ओपी के अंकन का उपयोग करना यह होगा(A && B) | C


आइए एक और उदाहरण लेते हैं:

$ echo foo | false &&  echo 123 | tr 2 5
$

यहां हमारे पास एक सूची है <pipeline1> && <pipeline2>। चूंकि हम जानते हैं कि पाइपलाइन की निकास स्थिति अंतिम कमांड के समान है और falseनकारात्मक स्थिति उर्फ ​​असफलता लौटाती है, &&दाहिने हाथ की तरफ निष्पादित नहीं होगी।

$ echo foo | true &&  echo 123 | tr 2 5
153

यहां बाएं पाइप लाइन को सफलता से बाहर निकलने की स्थिति है, इसलिए सही पाइपलाइन निष्पादित की जाती है और हम इसका आउटपुट देखते हैं।


ध्यान दें कि शेल व्याकरण वास्तविक निष्पादन आदेश का अर्थ नहीं करता है। गिल्स के जवाब में से किसी एक को उद्धृत करने के लिए :

पाइप्ड कमांड समवर्ती रूप से चलते हैं। जब आप ps चलाते हैं | grep…, यह ड्रा (या शेड्यूलर के साथ संयुक्त शेल के कामकाज के विवरण का मामला है, कर्नेल के आंत्र में गहरी ट्यूनिंग के साथ) क्या पीएस या ग्रीप पहले शुरू होता है, और किसी भी तरह से वे जारी रखते हैं समवर्ती रूप से निष्पादित करने के लिए।

और बैश मैनुअल से:

और या OR सूचियों को बाएं समरूपता के साथ निष्पादित किया जाता है।

कि में के आधार पर , पहले निष्पादित किया जाएगा यदि पिछला आदेश सफल होता है, लेकिन पहली बार एक प्रक्रिया के बजाय पैदा हो सकता है क्योंकि वे एक पाइप लाइन में हैं।cd ~/screenshots/ && ls screenshot* | head -n 5cd ~/screenshots/ls screenshot* | head -n 5head -n 5ls


1
मैं यह नहीं देखता कि प्रश्न कुछ भी पूछता है कि किन चीजों के लिए आदेश दिए गए हैं।
माइकल होमर

"इसकी कोई पूर्वता नहीं है, जिसमें से कोई पहले दिखाई देता है, cd ~/screenshots/ && ls screenshot*या head -n 5" ठीक है, हाँ, यही मामला है ((cd ~/screenshots/ && ls screenshot*) | head -n 5)। लेकिन यह अस्पष्ट मामले के बारे में कुछ भी नहीं कहता है cd ~/screenshots/ && ls screenshot* | head -n 5जो प्रश्न का बिंदु (आसपास के कोष्ठक के साथ या बिना) लगता है।
इलकाचू

@ilkkachu अधिकार, लेकिन निम्नलिखित वाक्य उस पर स्पर्श करते हैं। cd ~/screenshots/ && ls screenshot* पहले संसाधित करना होगा क्योंकि &&सूचियाँ पूर्वता के क्रम पर अधिक होती हैं (l0b0 के उत्तर के आधार पर, कम से कम)। आपको कहां लगता है कि मुझे उत्तर में सुधार करना चाहिए?
सर्गी कोलोडियाज़नी

@SergiyKolodyazhnyy, ठीक है, यह देखते हुए कि प्रश्न दोनों में है (cd && ls | head)और ((cd && ls) | head), यह स्पष्ट होना अच्छा हो सकता है कि आपका कौन सा मतलब है।
इलकाचू

@ilkachachu ठीक है, मैं इसे अभी के लिए हटाने जा रहा हूं, और इस बीच इसे संपादित कर दूंगा
सर्गी कोलोडियाज़नी

3

यहाँ यह निर्दिष्ट किया गया है bash(1):

SHELL GRAMMAR
[...]
   Pipelines
       A  pipeline  is  a sequence of one or more commands separated by one of
       the control operators | or |&.
[...]
   Lists
       A list is a sequence of one or more pipelines separated by one  of  the
       operators ;, &, &&, or ||, and optionally terminated by one of ;, &, or
       <newline>.

इसलिए, &&पाइपलाइनों को अलग करता है।


2

आप बस कोशिश कर सकते हैं echo hello && echo world | less। आप देखेंगे कि |उच्च वरीयता है (कमांडों का एक पाइप लाइन एक कमांड है)। आपके दूसरे उदाहरण के लिए समान नहीं है। हालाँकि cd, इसका कोई आउटपुट नहीं है, इसलिए आपको कोई अंतर नहीं दिखेगा।

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