सेट-ई का मतलब बैश स्क्रिप्ट में क्या है?


713

मैं इस प्रीस्टीन फ़ाइल की सामग्री का अध्ययन कर रहा हूं, जो उस पैकेज से पहले स्क्रिप्ट निष्पादित करती है, इसकी डेबियन आर्काइव (.deb) फ़ाइल से अनपैक की गई है।

स्क्रिप्ट में निम्न कोड है:

#!/bin/bash
set -e
# Automatically added by dh_installinit
if [ "$1" = install ]; then
   if [ -d /usr/share/MyApplicationName ]; then
     echo "MyApplicationName is just installed"
     return 1
   fi
   rm -Rf $HOME/.config/nautilus-actions/nautilus-actions.conf
   rm -Rf $HOME/.local/share/file-manager/actions/*
fi
# End automatically added section

मेरी पहली क्वेरी लाइन के बारे में है:

set -e

मुझे लगता है कि बाकी स्क्रिप्ट बहुत सरल है: यह जांचता है कि क्या डेबियन / उबंटू पैकेज मैनेजर एक इंस्टॉल ऑपरेशन को अंजाम दे रहा है। यदि यह है, तो यह जांचता है कि क्या मेरा आवेदन सिस्टम पर अभी स्थापित किया गया है। यदि यह है, तो स्क्रिप्ट "MyApplicationName बस स्थापित है" संदेश को प्रिंट करता है और समाप्त होता है ( return 1इसका मतलब है कि "त्रुटि" के साथ समाप्त होता है, है ना?)।

यदि उपयोगकर्ता मेरे पैकेज को स्थापित करने के लिए डेबियन / उबंटू पैकेज सिस्टम से पूछ रहा है, तो स्क्रिप्ट भी दो निर्देशिकाओं को हटा देती है।

क्या यह सही है या मुझे कुछ याद आ रहा है?



46
कारण यह है कि आप इसे Google में नहीं ढूंढ सकते हैं: -इसमें आपकी क्वेरी को नकार के रूप में समझा जाता है। निम्नलिखित क्वेरी आज़माएँ: bash set "-e"
मालेव

3
@twalberg जब मैंने खुद से वही सवाल पूछा है, तो मैं देख रहा थाman set
Sedat Kilinc

4
अगर आप इसे बंद करना चाहते हैं, तो डैश को प्लस प्रीफ़िक्स पर स्वैप करें:set +e
टॉम सालेबा

@twalberg लेकिन वास्तविक लोगों से पूछना एक रोबोट ;-) से अनुरोध करने की तुलना में बहुत अधिक दिलचस्प है।
vdegenne

जवाबों:


797

से help set:

  -e  Exit immediately if a command exits with a non-zero status.

लेकिन इसे कुछ लोगों द्वारा बुरा व्यवहार माना जाता है (bash FAQ and irc freenode #bash FAQ लेखक)। यह उपयोग करने के लिए अनुशंसित है:

trap 'do_something' ERR

do_somethingत्रुटि होने पर फ़ंक्शन चलाने के लिए ।

Http://mywiki.wooledge.org/BashFAQ/105 देखें


14
Do_something क्या होगा यदि मैं एक ही शब्दार्थ को "बाहर निकलना चाहता हूं यदि कोई कमांड गैर-शून्य स्थिति के साथ बाहर निकलता है"?
CMCDragonkai

71
trap 'exit' ERR
चेपनर

12
ERRजाल खोल कार्यों को विरासत में नहीं है, इसलिए यदि आप कार्य होते हैं, set -o errtraceया set -Eआप बस एक बार जाल सेट करने की अनुमति है और यह विश्व स्तर पर लागू होगी।
ykay

31
कुछ अलग करता trap 'exit' ERRहै ? set -e
एंडी

22
यदि यह बुरा अभ्यास है तो डेबियन पैकेज में इसका उपयोग क्यों किया जाता है ?
फुलकव

98

set -eस्क्रिप्ट के निष्पादन को रोकता है यदि कमांड या पाइपलाइन में त्रुटि है - जो कि डिफ़ॉल्ट शेल व्यवहार के विपरीत है, जो स्क्रिप्ट में त्रुटियों को अनदेखा करना है। टाइप help setएक टर्मिनल में इस में निर्मित आदेश के लिए दस्तावेज़ को देखने के लिए।


44
यह केवल निष्पादन को रोकता है यदि पाइप लाइन में अंतिम कमांड में कोई त्रुटि है। एक बैश विशिष्ट विकल्प है, set -o pipefailजिसका उपयोग त्रुटियों को प्रचारित करने के लिए किया जा सकता है ताकि पाइपलाइन कमांड का वापसी मूल्य गैर-शून्य हो अगर गैर-शून्य स्थिति के साथ बाहर निकलने वाले पूर्ववर्ती आदेशों में से एक।
एन्थोनी गेघेगन

2
ध्यान रखें कि -o pipefailइसका अर्थ केवल यह है कि पाइप लाइन की पहली गैर-शून्य (यानी शर्तों में त्रुटिपूर्ण ) कमांड का निकास स्थिति-o errexit अंत तक प्रचारित है। पाइपलाइन में शेष कमांड अभी भी चलते हैं , साथ ही set -o errexit। उदाहरण के लिए: echo success | cat - <(echo piping); echo continues, जहां echo successएक सफल, लेकिन अविश्वसनीय आदेश का प्रतिनिधित्व करता है, प्रिंट होगा success, pipingहै, और continues, लेकिन false | cat - <(echo piping); echo continues, साथ falseअब आदेश का प्रतिनिधित्व चुपचाप erroring, अभी भी प्रिंट होगा pipingबाहर निकलने से पहले।
bb010g

54

बैश के अनुसार - सेट बेसिन मैनुअल, अगर -e/ errexitसेट है, तो शेल तुरंत बाहर निकलता है अगर एक एकल साधारण कमांड से युक्त एक पाइपलाइन , एक सूची या एक कंपाउंड कमांड एक गैर-शून्य स्थिति देता है।

डिफ़ॉल्ट रूप से, पाइपलाइन की निकास स्थिति पाइपलाइन में अंतिम कमांड की निकास स्थिति है, जब तक कि pipefailविकल्प सक्षम नहीं होता है (यह डिफ़ॉल्ट रूप से अक्षम है)।

यदि ऐसा है, तो पाइप लाइन की अंतिम स्थिति (सबसे दाएं) की कमांड गैर-शून्य स्थिति से बाहर निकलने के लिए है, या यदि सभी कमांड सफलतापूर्वक बाहर निकलते हैं।

यदि आप बाहर निकलने पर कुछ निष्पादित करना चाहते हैं trap, तो उदाहरण के लिए परिभाषित करने का प्रयास करें :

trap onexit EXIT

onexitबाहर निकलने पर कुछ करने का आपका कार्य कहां है, जैसे नीचे सरल स्टैक ट्रेस प्रिंट कर रहा है :

onexit(){ while caller $((n++)); do :; done; }

इसी तरह का विकल्प है -E /errtrace जो ईआरआर के बजाय फँस जाएगा, जैसे:

trap onerr ERR

उदाहरण

शून्य स्थिति उदाहरण:

$ true; echo $?
0

गैर-शून्य स्थिति उदाहरण:

$ false; echo $?
1

नकारात्मक स्थिति उदाहरण:

$ ! false; echo $?
0
$ false || true; echo $?
0

के साथ टेस्ट करें pipefailविकलांग होने के :

$ bash -c 'set +o pipefail -e; true | true | true; echo success'; echo $?
success
0
$ bash -c 'set +o pipefail -e; false | false | true; echo success'; echo $?
success
0
$ bash -c 'set +o pipefail -e; true | true | false; echo success'; echo $?
1

pipefailसक्षम होने के साथ टेस्ट करें :

$ bash -c 'set -o pipefail -e; true | false | true; echo success'; echo $?
1

54

मुझे यह पोस्ट यह पता लगाने की कोशिश करते हुए मिली कि एग्जिट स्टेटस एक स्क्रिप्ट की वजह से था जिसे ए की वजह से खत्म कर दिया गया था set -e। उत्तर मुझे स्पष्ट नहीं दिखाई दिया; इसलिए यह जवाब। मूल रूप से, set -eएक कमांड के निष्पादन को रोकता है (जैसे एक शेल स्क्रिप्ट) और कमांड का निकास स्थिति कोड लौटाता है जो विफल हो गया (यानी आंतरिक स्क्रिप्ट, बाहरी स्क्रिप्ट नहीं)

उदाहरण के लिए, मान लें कि मेरे पास शेल स्क्रिप्ट है outer-test.sh:

#!/bin/sh
set -e
./inner-test.sh
exit 62;

के लिए कोड inner-test.shहै:

#!/bin/sh
exit 26;

जब मैं outer-script.shकमांड लाइन से चलता हूं, तो मेरी बाहरी स्क्रिप्ट आंतरिक स्क्रिप्ट के निकास कोड के साथ समाप्त हो जाती है:

$ ./outer-test.sh
$ echo $?
26

10

मेरा मानना ​​है कि इरादा तेजी से विफल होने के लिए स्क्रिप्ट के लिए है।

इसे स्वयं जांचने के लिए, बस set -eएक bash प्रॉम्प्ट पर टाइप करें । अब, दौड़ने का प्रयास करें ls। आपको निर्देशिका सूची मिल जाएगी। अब, टाइप करें lsd। वह आदेश पहचाना नहीं गया है और एक त्रुटि कोड लौटाएगा, और इसलिए आपका बैश प्रॉम्प्ट (कारण set -e) बंद हो जाएगा ।

अब, इसे 'स्क्रिप्ट' के संदर्भ में समझने के लिए, इस सरल स्क्रिप्ट का उपयोग करें:

#!/bin/bash 
# set -e

lsd 

ls

यदि आप इसे वैसे ही चलाते हैं, तो आपको lsअंतिम पंक्ति में निर्देशिका सूची मिल जाएगी । यदि आप इसे अनकम्प्लीट करते हैं set -eऔर फिर से चलाते हैं, तो आपको डायरेक्ट्री लिस्टिंग दिखाई नहीं देगी क्योंकि बैश प्रोसेसिंग बंद हो जाता है क्योंकि यह त्रुटि से सामना करता है lsd


क्या यह उत्तर किसी भी जानकारी या जानकारी को जोड़ता है जो पहले से ही प्रश्न पर दूसरों में नहीं दी गई थी?
चार्ल्स डफी

6
मुझे लगता है कि यह कार्यक्षमता का एक स्पष्ट, संक्षिप्त विवरण प्रदान करता है जो अन्य उत्तरों में मौजूद नहीं है। अतिरिक्त कुछ भी नहीं, बस अन्य प्रतिक्रियाओं की तुलना में अधिक ध्यान केंद्रित किया।
कालिन नागेलबर्ग

9

यह एक पुराना सवाल है, लेकिन यहां कोई भी उत्तर डेबियन पैकेज हैंडलिंग स्क्रिप्ट में set -eउर्फ के उपयोग पर चर्चा नहीं करता है set -o errexit। इन लिपियों में, डेबियन नीति के अनुसार इस विकल्प का उपयोग अनिवार्य है; आशय स्पष्ट रूप से एक अनहेल्ड त्रुटि स्थिति की किसी भी संभावना से बचने के लिए है।

व्यवहार में इसका मतलब यह है कि आपको यह समझना होगा कि आपके द्वारा चलाए जा रहे कमांड किस स्थिति में एक त्रुटि लौटा सकते हैं, और उन त्रुटियों में से प्रत्येक को स्पष्ट रूप से संभाल सकते हैं।

आम गोच उदाहरण हैं diff(एक अंतर grepहोने पर एक त्रुटि देता है ) और (एक मैच नहीं होने पर एक त्रुटि देता है)। आप स्पष्ट हैंडलिंग के साथ त्रुटियों से बच सकते हैं:

diff this that ||
  echo "$0: there was a difference" >&2
grep cat food ||
  echo "$0: no cat in the food" >&2

(यह भी देखें कि हम संदेश में वर्तमान स्क्रिप्ट के नाम को शामिल करने के लिए कैसे ध्यान रखते हैं, और मानक उत्पादन के बजाय मानक त्रुटि के लिए नैदानिक ​​संदेश लिख रहे हैं।)

यदि कोई स्पष्ट हैंडलिंग वास्तव में आवश्यक या उपयोगी नहीं है, तो स्पष्ट रूप से कुछ भी न करें:

diff this that || true
grep cat food || :

(शेल के :नो-ऑप कमांड का उपयोग थोड़ा अस्पष्ट है, लेकिन आमतौर पर देखा जाता है।)

बस दोहराना है,

something || other

के लिए आशुलिपि है

if something; then
    : nothing
else
    other
fi

यानी हम स्पष्ट रूप से कहते हैं कि otherअगर और केवल somethingविफल हो तो चलाया जाना चाहिए । लॉन्गहैंड if(और अन्य शेल फ्लो कंट्रोल स्टेटमेंट जैसे while, until) एक एरर को हैंडल करने का एक वैध तरीका है (वास्तव में, अगर यह नहीं था, तो शेलset -e में फ्लो कंट्रोल स्टेटमेंट नहीं हो सकते!)

और यह भी, बस स्पष्ट होने के लिए, इस तरह के एक हैंडलर की अनुपस्थिति में, set -eयदि diffकोई अंतर पाया गया, या grepएक मैच नहीं मिला , तो पूरी स्क्रिप्ट त्रुटि के साथ तुरंत विफल हो जाएगी।

दूसरी ओर, कुछ कमांड्स त्रुटि निकास स्थिति का उत्पादन नहीं करते हैं जब आप उन्हें चाहते हैं। सामान्य रूप से समस्याग्रस्त कमांड हैं find(बाहर निकलने की स्थिति प्रतिबिंबित नहीं करती है कि क्या फाइलें वास्तव में मिली थीं) और sed(बाहर निकलने की स्थिति से पता नहीं चलेगा कि स्क्रिप्ट को कोई इनपुट प्राप्त हुआ या वास्तव में किसी भी कमांड को सफलतापूर्वक निष्पादित किया गया है)। कुछ परिदृश्यों में एक साधारण गार्ड एक कमांड पर पाइप करना है जो आउटपुट नहीं होने पर चिल्लाता है:

find things | grep .
sed -e 's/o/me/' stuff | grep ^

यह ध्यान दिया जाना चाहिए कि पाइपलाइन की निकास स्थिति उस पाइपलाइन में अंतिम कमांड की निकास स्थिति है। इसलिए उपरोक्त आदेश वास्तव में findऔर की स्थिति को पूरी तरह से मुखौटा करते हैं sed, और केवल आपको बताते हैं कि क्या grepअंत में सफल हुआ।

(बैश, ज़ाहिर है set -o pipefail, लेकिन; डेबियन पैकेज स्क्रिप्ट बैश सुविधाओं का उपयोग नहीं कर सकते। नीति shइन लिपियों के लिए POSIX के उपयोग को दृढ़ता से निर्धारित करती है , हालांकि यह हमेशा ऐसा नहीं था।)

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


यह एक उत्कृष्ट उत्तर है। और यह सर्वोत्तम अभ्यास को बढ़ावा देता है। मैं grep कमांड से exactally एक ही समस्या थी और मैं वास्तव में 'सेट -e' दूर करने के लिए नहीं करना चाहता था
मिन्नी शि

7
Script 1: without setting -e
#!/bin/bash
decho "hi"
echo "hello"
This will throw error in decho and program continuous to next line

Script 2: With setting -e
#!/bin/bash
set -e
decho "hi" 
echo "hello"
# Up to decho "hi" shell will process and program exit, it will not proceed further
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.