एक चर असाइनमेंट की वापसी स्थिति कैसे निर्धारित की जाती है?


10

मैंने निर्माण को इस तरह से स्क्रिप्ट में देखा है:

if somevar="$(somecommand 2>/dev/null)"; then
...
fi

क्या यह कहीं दस्तावेज है? एक चर की वापसी की स्थिति कैसे निर्धारित की जाती है और यह कमांड प्रतिस्थापन से कैसे संबंधित है? (उदाहरण के लिए, मैं एक ही परिणाम के साथ मिल जाएगा if echo "$(somecommand 2>/dev/null)"; then?)

जवाबों:


13

यह ओपन ग्रुप बेस स्पेसिफिकेशंस के सेक्शन 2.9.1 सिंपल कमांड्स में से (POSIX के लिए) प्रलेखित है । वहाँ पाठ की एक दीवार है; मैं अंतिम पैराग्राफ पर आपका ध्यान निर्देशित करता हूं:

यदि कमांड नाम है, तो कमांड सर्च एंड एक्ज़ेक्यूशन में वर्णित अनुसार निष्पादन जारी रहेगा । यदि कोई कमांड नाम नहीं है, लेकिन कमांड में कमांड प्रतिस्थापन है, कमांड अंतिम कमांड प्रतिस्थापन के निकास की स्थिति के साथ पूरा होगा। अन्यथा, कमांड शून्य निकास स्थिति के साथ पूरा होगा।

इसलिए, उदाहरण के लिए,

   Command                                         Exit Status
$ FOO=BAR                                   0 (but see also the note from icarus, below)
$ FOO=$(bar)                                Exit status from "bar"
$ FOO=$(bar) baz                            Exit status from "baz"
$ foo $(bar)                                Exit status from "foo"

यह कैसे काम करता है, भी है। लेकिन अंत में “इतना सरल नहीं” खंड भी देखें।

phk , उनके प्रश्न में असाइनमेंट एक कमांड स्थिति से बाहर निकलने की स्थिति की तरह है, जब कमांड प्रतिस्थापन है? , सुझाव देता है

... ऐसा प्रतीत होता है जैसे कि एक असाइनमेंट स्वयं एक कमांड के रूप में गिना जाता है ... एक शून्य निकास मान के साथ, लेकिन जो असाइनमेंट के दाईं ओर से पहले लागू होता है (जैसे, कमांड प्रतिस्थापन कॉल ...)

यह देखने का एक भयानक तरीका नहीं है। एक साधारण आदेश की वापसी स्थिति का निर्धारण करने के लिए एक कच्चे योजना (एक युक्त नहीं ;, &, |, &&या ||) है:

  • अंत या एक कमांड शब्द (आमतौर पर एक प्रोग्राम का नाम) तक पहुंचने तक बाएं से दाएं लाइन को स्कैन करें।
  • यदि आप एक चर असाइनमेंट देखते हैं, तो लाइन के लिए रिटर्न की स्थिति सिर्फ 0 हो सकती है।
  • यदि आप एक कमांड प्रतिस्थापन देखते हैं - अर्थात, $(…)- उस कमांड से निकास की स्थिति लें।
  • यदि आप एक वास्तविक कमांड (कमांड प्रतिस्थापन में नहीं) तक पहुंचते हैं, तो उस कमांड से निकास की स्थिति लें।
  • लाइन के लिए वापसी की स्थिति आपके पास अंतिम संख्या है।
    कमांड के तर्क के रूप में कमांड प्रतिस्थापन , जैसे, foo $(bar)गिनती नहीं; आपको बाहर निकलने की स्थिति मिलती है fooPhp की संकेतन paraphrase करने के लिए , यहाँ व्यवहार है

    temporary_variable  = EXECUTE( "bar" )
    overall_exit_status = EXECUTE( "foo", temporary_variable )
    

लेकिन यह एक मामूली ओवरसिलेशन है। से समग्र वापसी की स्थिति

A = $ ( cmd 1 ) B = $ ( cmd 2 ) C = $ ( cmd 3 ) D = $ ( cmd 4 ) E = mc 2
से बाहर निकलने की स्थिति है । काम के बाद आती है काम 0 के लिए समग्र बाहर निकलें स्थिति निर्धारित नहीं करता है।cmd4E=D=

icarus , phk के सवाल के अपने जवाब में , एक महत्वपूर्ण बिंदु उठाता है: चर को आसानी से सेट किया जा सकता है। पोसिक्स मानक के खंड 2.9.1 में तीसरा-से-अंतिम पैराग्राफ कहता है,

यदि कोई भी चर असाइनमेंट एक वैरिएबल के लिए एक मान निर्दिष्ट करने का प्रयास करता है जिसके लिए वर्तमान शेल वातावरण में रीडऑनली विशेषता सेट की जाती है (चाहे उस वातावरण में असाइनमेंट बनाया गया हो), तो एक चर असाइनमेंट त्रुटि होगी। इन त्रुटियों के परिणामों के लिए शेल त्रुटियों के परिणाम देखें ।

अगर तुम कहो तो

readonly A
C=Garfield A=Felix T=Tigger

वापसी स्थिति 1. है यह नहीं बात करता है, तो तार Garfield, Felixऔर / या Tigger आदेश प्रतिस्थापन (रों) के साथ प्रतिस्थापित कर रहे हैं - लेकिन नीचे नोट देखें।

2.8.1.1 शैल त्रुटियों के परिणाम में पाठ का एक और गुच्छा है, और एक तालिका है, और इसके साथ समाप्त होती है

तालिका में दिखाए गए सभी मामलों में जहां एक इंटरैक्टिव शेल को बाहर निकलने की आवश्यकता नहीं है, शेल उस कमांड का कोई और प्रसंस्करण नहीं करेगा जिसमें त्रुटि हुई थी।

कुछ विवरण समझ में आते हैं; कुछ नहीं:

  • A=काम कभी कभी रोकता के रूप में है कि अंतिम वाक्य निर्दिष्ट करने के लिए लगता है, कमांड लाइन। उपरोक्त उदाहरण में, के Cलिए सेट है Garfield, लेकिन Tसेट नहीं है (और, ज़ाहिर है, न तो है  A)।
  • इसी तरह, निष्पादित करता है , लेकिन नहीं । लेकिन, मेरे बैश के संस्करणों में (जिसमें 4.1.X और 4.3.X शामिल हैं), यह निष्पादित करता है । (संयोग से, यह phk की व्याख्या को आगे बढ़ाता है कि असाइनमेंट का निकास मान असाइनमेंट के दाईं ओर से पहले लागू होता है।)C=$(cmd1) A=$(cmd2) T=$(cmd3)cmd1cmd3
    cmd2

लेकिन यहाँ एक आश्चर्य है:

बाश के मेरे संस्करणों में,

आसानी से ए
सी = कुछ ए = कुछ टी = कुछ  सीएमडी 0

निष्पादित करता है । विशेष रूप से,cmd0

C = $ ( cmd 1 ) A = $ ( cmd 2 ) T = $ ( cmd 3 )    cmd 0
निष्पादित और , लेकिन नहीं । (ध्यान दें कि यह उसके व्यवहार के विपरीत है जब कोई आदेश नहीं है।) और यह पर्यावरण में (साथ ही साथ ) सेट करता है । मुझे आश्चर्य है कि क्या यह बग में एक बग है।cmd1cmd3cmd2TCcmd0


इतना आसान नहीं:

इस उत्तर का पहला पैराग्राफ "साधारण कमांड" को संदर्भित करता है।  विनिर्देश कहता है,

एक "सरल कमांड" वैकल्पिक चर असाइनमेंट और पुनर्निर्देशन का एक क्रम है, किसी भी क्रम में, वैकल्पिक रूप से शब्दों और पुनर्निर्देशन के बाद, एक नियंत्रण ऑपरेटर द्वारा समाप्त किया जाता है।

ये मेरे पहले उदाहरण ब्लॉक में दिए गए कथन हैं:

$ FOO=BAR
$ FOO=$(bar)
$ FOO=$(bar) baz
$ foo $(bar)

जिनमें से पहले तीन में परिवर्तनशील कार्य शामिल हैं, और अंतिम तीन में कमांड प्रतिस्थापन शामिल हैं।

लेकिन कुछ परिवर्तनशील कार्य बहुत सरल नहीं हैं।  बैश (1) कहता है,

असाइनमेंट बयान भी करने के लिए तर्क के रूप में दिखाई दे सकते हैं alias, declare, typeset, export, readonly, और localअंतर्निहित आदेश ( घोषणा आदेशों)।

के लिए export, POSIX विनिर्देश कहता है,

बाहर निकलें स्थिति

    0
      सभी नाम ऑपरेंड सफलतापूर्वक निर्यात किए गए थे।
    > 0
      कम से कम एक नाम निर्यात नहीं किया जा सकता है, या -pविकल्प निर्दिष्ट किया गया था और एक त्रुटि हुई।

और POSIX समर्थन नहीं करता है local, लेकिन बैश (1) कहता है,

यह localएक समारोह के भीतर नहीं जब उपयोग करने के लिए एक त्रुटि है । वापसी की स्थिति 0 है जब तक localकिसी फ़ंक्शन के बाहर उपयोग नहीं किया जाता है, एक अमान्य नाम की आपूर्ति की जाती है, या नाम एक पठनीय चर है।

लाइनों के बीच में पढ़ते हुए, हम उस घोषणा आदेश को देख सकते हैं जैसे

export FOO=$(bar)

तथा

local FOO=$(bar)

अधिक पसंद हैं

foo $(bar)

जहां तक वे से बाहर निकलने स्थिति पर ध्यान न दें bar और आप मुख्य कमान के आधार पर एक निकास दर्जा देने ( export, local, या foo)। तो हमारे पास अजीब तरह का है

   Command                                           Exit Status
$ FOO=$(bar)                                    Exit status from "bar"
                                                  (unless FOO is readonly)
$ export FOO=$(bar)                             0 (unless FOO is readonly,
                                                  or other error from “export”)
$ local FOO=$(bar)                              0 (unless FOO is readonly,
                                                  statement is not in a function,
                                                  or other error from “local”)

जिसे हम प्रदर्शित कर सकते हैं

$ export FRIDAY=$(date -d tomorrow)
$ echo "FRIDAY   = $FRIDAY, status = $?"
FRIDAY   = Fri, May 04, 2018  8:58:30 PM, status = 0
$ export SATURDAY=$(date -d "day after tomorrow")
date: invalid date ‘day after tomorrow’
$ echo "SATURDAY = $SATURDAY, status = $?"
SATURDAY = , status = 0

तथा

myfunc() {
    local x=$(echo "Foo"; true);  echo "x = $x -> $?"
    local y=$(echo "Bar"; false); echo "y = $y -> $?"
    echo -n "BUT! "
    local z; z=$(echo "Baz"; false); echo "z = $z -> $?"
}

$ myfunc
x = Foo -> 0
y = Bar -> 0
BUT! z = Baz -> 1

सौभाग्य से शेलचेक त्रुटि पकड़ता है और SC2155 उठाता है , जो सलाह देता है

export foo="$(mycmd)"

को बदलना चाहिए

foo=$(mycmd)
export foo

तथा

local foo="$(mycmd)"

को बदलना चाहिए

local foo
foo=$(mycmd)

1
बहुत बहुत धन्यवाद! बोनस अंक के लिए, क्या आप जानते हैं कि इसमें कैसे localसंबंध हैं? जैसे local foo=$(bar)?
वाइल्डकार्ड

1
दूसरे उदाहरण के लिए (सिर्फ FOO=$(bar)) यह ध्यान देने योग्य है कि सैद्धांतिक रूप से बाहर निकलने की स्थिति और असाइनमेंट दोनों एक भूमिका निभा सकते हैं, देखें unix.stackexchange.com/a/341013/117599
phk

1
@Wildcard: मुझे खुशी है कि आप इसे पसंद करेंगे। मैंने इसे फिर से अपडेट किया है; आपके द्वारा अभी पढ़ा गया संस्करण का एक बड़ा हिस्सा गलत था। जब तक आप यहाँ हैं, आप क्या सोचते हैं? क्या यह बग में एक बग है, जो केवल पढ़ने पर भी A=foo cmdचलता है? cmdA
जी-मैन का कहना है कि 'मोनिका'

1
@ एफके: (1) दिलचस्प सिद्धांत, लेकिन मुझे यकीन नहीं है कि यह कैसे समझ में आता है। मेरे "आश्चर्य" शीर्षक से ठीक पहले उदाहरण पर एक और नज़र डालें। यदि आसानी Aसे, कमांड C=value₁ A=value₂ T=value₃सेट होता है, Cलेकिन T(और, निश्चित रूप से, Aसेट नहीं है) - शेल कमांड लाइन को अनदेखा करते हुए प्रसंस्करण को समाप्त करता है T=value₃, क्योंकि A=value₂एक त्रुटि है। (2) स्टैक ओवरफ्लो प्रश्न के लिंक के लिए धन्यवाद - मैंने इस पर टिप्पणी पोस्ट की है।
जी-मैन का कहना है

1
@Wildcard "बोनस अंक के लिए, क्या आप जानते हैं कि इसमें स्थानीय संबंध कैसे हैं?"। हाँ ... local=$(false)निकास मान है 0(क्योंकि मैन पेज से) It is an error to use local when not within a function. The return status is 0 unless local is used outside a function, an invalid name is supplied, or name is a readonly variable.:। यह इस तरह से डिजाइन किए गए जीनियस के लिए दुनिया पर पर्याप्त ट्रोलफेस नहीं है।
डेविड टोनहोफर

2

यह बाश में प्रलेखित है ( LESS=+/'^SIMPLE COMMAND EXPANSION' bash):

यदि विस्तार के बाद कोई कमांड नाम शेष है ... अन्यथा, कमांड से बाहर निकलता है। ... यदि कोई कमांड प्रतिस्थापन नहीं थे, तो कमांड शून्य की स्थिति के साथ बाहर निकलता है।

दूसरे शब्दों में (मेरे शब्द):

यदि विस्तार के बाद कोई कमांड नाम नहीं बचा है, और कोई कमांड प्रतिस्थापन निष्पादित नहीं किया गया था, तो कमांड लाइन शून्य की स्थिति के साथ बाहर निकलती है।

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