मैं पाइपफेल के समान तरीके से बैकटिक विफलता पर बाहर निकलने के लिए कैसे बैश हो सकता हूं?


55

इसलिए मैं अपनी बैश लिपियों को कड़ा करना पसंद करता हूं, जहां भी हो सकता है (और जब पाइथन / रूबी जैसी भाषा को सौंपने में सक्षम नहीं) तो यह सुनिश्चित करने के लिए कि त्रुटियों को अनसुना न करें।

उस नस में मेरे पास एक सख्त.श है, जिसमें चीजें शामिल हैं:

set -e
set -u
set -o pipefail

और इसे अन्य लिपियों में स्रोत। हालांकि, जबकि पिपफेल उठा होगा:

false | echo it kept going | true

यह नहीं उठाएगा:

echo The output is '`false; echo something else`' 

आउटपुट होगा

आउटपुट '' है

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

तो - वहाँ एक तरीका है बाहर निकलने के लिए पर्याप्त के रूप में एक बैकटिक के अंदर एक गैर-शून्य रिटर्नकोड का इलाज करने के लिए बैश हो सकता है?

जवाबों:


51

सटीक में प्रयुक्त भाषा एकल यूनिक्स विशिष्टता का वर्णन करने के का अर्थset -e है:

जब यह विकल्प चालू होता है, यदि कोई साधारण आदेश शेल त्रुटियों के परिणामों में सूचीबद्ध किसी भी कारण से विफल हो जाता है या निकास स्थिति मान> 0 लौटाता है, और [सशर्त या नकारात्मक आदेश] नहीं है, तो शेल तुरंत बाहर निकल जाएगा।

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

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

ध्यान दें कि यह केवल एक ही कमांड प्रतिस्थापन के रूप में यदि केवल अंतिम प्रतिस्थापन की स्थिति को ध्यान में रखा जाता है, तो यह प्रदर्शन करेगा। उदाहरण के लिए, निम्न कमांड सफल है (मानक के अनुसार और मेरे द्वारा देखे गए प्रत्येक कार्यान्वयन में):

a=$(false)$(echo foo)

के लिए देखने के लिए एक और मामला है स्पष्ट subshells : (somecommand)। ऊपर की व्याख्या के अनुसार, उपधारा एक गैर-स्थिति को वापस कर सकती है, लेकिन चूंकि यह मूल शेल में एक साधारण कमांड नहीं है, इसलिए मूल शेल जारी रखना चाहिए। वास्तव में, मुझे पता है कि सभी गोले इस बिंदु पर माता-पिता को वापस कर देते हैं। जबकि यह कई मामलों में उपयोगी होता है जैसे (cd /some/dir && somecommand)कि कोष्ठक का उपयोग ऑपरेशन को रखने के लिए किया जाता है जैसे कि वर्तमान निर्देशिका परिवर्तन स्थानीय, यह उप-धारा set -eमें बंद होने पर विनिर्देश का उल्लंघन करता है, या यदि उप-अंश एक तरह से नॉनजेरो स्थिति देता है तो इसे समाप्त नहीं करेगा, जैसे कि !एक सच्चे आदेश पर उपयोग करना। उदाहरण के लिए, fooनिम्नलिखित उदाहरणों को प्रदर्शित किए बिना ऐश, बैश, पीडीक्ष, ksh93 और zsh निकास के सभी :

set -e; (set +e; false); echo "This should be displayed"
set -e; (! true); echo "This should be displayed"

फिर भी कोई सरल आदेश set -eप्रभाव में रहने के दौरान विफल रहा है!

एक तीसरा समस्याग्रस्त मामला एक नॉनट्रिवियल पाइपलाइन में तत्व है । व्यवहार में, सभी गोले पिछले एक के अलावा पाइपलाइन के तत्वों की विफलताओं को नजरअंदाज करते हैं, और अंतिम पाइपलाइन तत्व के बारे में दो व्यवहारों में से एक का प्रदर्शन करते हैं:

  • ATT ksh और zsh, जो मूल शेल में पाइपलाइन के अंतिम तत्व को निष्पादित करते हैं, हमेशा की तरह व्यवसाय करते हैं: यदि पाइप लाइन के अंतिम तत्व में एक साधारण कमांड विफल रहता है, तो शेल उस कमांड को निष्पादित करता है, जो मूल शेल होता है, बाहर निकलता है।
  • अन्य गोले बाहर निकलने से व्यवहार को अनुमानित करते हैं यदि पाइप लाइन का अंतिम तत्व एक नॉनज़रो स्थिति देता है।

पहले की तरह, set -eपाइप लाइन के अंतिम तत्व में एक नकार को बंद करने या उपयोग करने से यह एक गैर-स्थिति को इस तरह से वापस करने का कारण बनता है जो शेल को समाप्त नहीं करना चाहिए; ATT ksh और zsh के अलावा अन्य गोले तब बाहर निकलेंगे।

बैश के pipefailविकल्प के तहत पाइप लाइन तुरंत बाहर निकलने का कारण बनती है set -eयदि इसके किसी भी तत्व को नॉनज़रो का दर्जा दिया जाता है।

ध्यान दें कि एक और जटिलता के रूप में, set -eजब तक यह पॉसिक्स मोड में नहीं हो जाता है ( set -o posixया POSIXLY_CORRECTबैश शुरू होने पर वातावरण में होता है) तक सबश में बंद हो जाता है ।

यह सब दिखाता है कि POSIX विनिर्देश दुर्भाग्य से -eविकल्प को निर्दिष्ट करने में खराब काम करता है । सौभाग्य से, मौजूदा गोले ज्यादातर उनके व्यवहार में सुसंगत हैं।


इसके लिए धन्यवाद। मेरे पास एक अनुभव यह था कि बैश के बाद के संस्करण में पकड़े गए कुछ त्रुटियों को सेट -e के साथ पहले के संस्करणों में अनदेखा किया गया था। यहां मेरा इरादा स्क्रिप्ट को इस हद तक सख्त करना है कि किसी भी गैर-संभाला त्रुटि वापसी / विफलता की स्थिति एक स्क्रिप्ट से बाहर निकल जाएगी। यह एक विरासत प्रणाली में है, जो कचरा आउटपुट फाइलों और गलत एन्व के साथ अराजकता के आधे घंटे के बाद "0" खुश निकास कोड का उत्पादन करने के लिए जाना जाता है - जब तक आप आउटपुट को एक हॉक की तरह नहीं देख रहे थे (और सभी त्रुटियों का नहीं stderr पर हैं, कुछ stdout पर हैं, और कुछ भाग / dev / null'd हैं), आपको अभी पता नहीं है।
डैनी स्टेपल

"उदाहरण के लिए, सभी राख, बाश, पीडीएसएच, ksh93 और zsh निम्नलिखित उदाहरणों पर फू प्रदर्शित किए बिना बाहर निकलते हैं": बिजीबॉक्स राख उस तरह से व्यवहार नहीं करता है, यह आउटपुट को कल्पना के अनुसार प्रदर्शित करता है। (बिजीबॉक्स 1.19.4 के साथ परीक्षण किया गया।) न ही इसके साथ बाहर निकलता है set -e; (cd /nonexisting)
दुबिज्जिम

27

(मेरा खुद का जवाब देना क्योंकि मैंने एक समाधान ढूंढ लिया है) एक समाधान यह है कि इसे हमेशा एक मध्यवर्ती चर को सौंपा जाए। इस तरह से वापसी ( $?) सेट है।

इसलिए

ABC=`exit 1`
echo $?

हालांकि आउटपुट 1(या इसके बजाय बाहर निकलता है तो set -eमौजूद है):

echo `exit 1`
echo $?

0रिक्त लाइन के बाद आउटपुट देगा । इको का रिटर्न कोड (या अन्य कमांड जो बैकटिक आउटपुट के साथ चलता है) 0 रिटर्न कोड को बदल देगा।

मैं अभी भी ऐसे समाधानों के लिए खुला हूं, जिन्हें मध्यवर्ती चर की आवश्यकता नहीं है, लेकिन इससे मुझे कुछ रास्ता मिल जाता है।


23

जैसा कि ओपी ने अपने स्वयं के उत्तर में बताया, सबकोमैंड के आउटपुट को एक चर में निर्दिष्ट करना समस्या का समाधान करता है; $?पूरा हुआ छोड़ दिया है।

हालांकि, एक किनारे का मामला अभी भी आपको गलत नकारात्मक के साथ पहेली बना सकता है (यानी कमांड विफल रहता है लेकिन त्रुटि बुलबुला नहीं करता है), localचर घोषणा:

local myvar=$(subcommand)होगा हमेशा वापसी 0!

bash(1) इसे इंगित करता है:

   local [option] [name[=value] ...]
          ... The return status is 0 unless local is used outside a function,
          an invalid name is supplied, or name is a readonly variable.

यहाँ एक साधारण परीक्षण मामला है:

#!/bin/bash

function test1() {
  data1=$(false) # undeclared variable
  echo 'data1=$(false):' "$?"
  local data2=$(false) # declaring and assigning in one go
  echo 'local data2=$(false):' "$?"
  local data3
  data3=$(false) # assigning a declared variable
  echo 'local data3; data3=$(false):' "$?"
}

test1

उत्पादन:

data1=$(false): 1
local data2=$(false): 0
local data3; data3=$(false): 1

धन्यवाद, बीच में विसंगति VAR=...और local VAR=...वास्तव में मुझे flummoxed!
जॉनी

13

जैसा कि दूसरों ने कहा है, localहमेशा 0. वापस आ जाएगा। समाधान पहले चर घोषित करने के लिए है:

function testcase()
{
    local MYRESULT

    MYRESULT=$(false)
    if (( $? != 0 )); then
        echo "False returned false!"
        return 1
    fi

    return 0
}

आउटपुट:

$ testcase
False returned false!
$ 

4

कमांड प्रतिस्थापन विफलता पर बाहर निकलने के लिए आप स्पष्ट रूप से -eइस तरह से सब- सेट कर सकते हैं :

set -e
x=$(set -e; false; true)
echo "this will never be shown"

1

दिलचस्प बात!

मैंने कभी भी उस पर ठोकर नहीं खाई है, क्योंकि मैं कोई दोस्त नहीं हूं set -e(इसके बजाय मैं पसंद करता हूं trap ... ERR) लेकिन पहले से ही परीक्षण किया गया है कि: या (या पुराने बैकस्टिक्स) के trap ... ERRभीतर त्रुटियों को भी न $(...)पकड़ें।

मुझे लगता है कि समस्या यह है (जैसा कि अक्सर होता है) कि यहां एक सब-कॉल कहा जाता है और -eस्पष्ट रूप से वर्तमान शेल का मतलब है ।

इस समय केवल अन्य समाधान जो मन में आया, वह होगा पढ़ने के लिए उपयोग:

 ls -l ghost_under_bed | read name

यह थ्रो ERRऔर -eशेल के साथ समाप्त हो जाएगा। केवल समस्या: यह केवल आउटपुट की एक पंक्ति के साथ कमांड के लिए काम करता है (या आप किसी ऐसी चीज से पाइप करते हैं जो लाइनों में मिलती है)।


1
रीड ट्रिक के बारे में निश्चित नहीं है, यह प्रयास करता है कि वैरिएबल बाध्य न हो। मुझे लगता है कि यह हो सकता है क्योंकि पाइप के दूसरे पक्ष को प्रभावी रूप से एक उपधारा है, नाम उपलब्ध नहीं होगा।
डैनी स्टेपल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.