यदि कोई कमांड नॉन-जीरो मान लौटाता है तो शेल स्क्रिप्ट को निरस्त करना?


437

मेरे पास एक बैश शेल स्क्रिप्ट है जो कई कमांड को आमंत्रित करती है। अगर कोई भी कमांड नॉन-जीरो वैल्यू लौटाता है, तो मैं शेल स्क्रिप्ट को अपने आप 1 के रिटर्न वैल्यू से बाहर निकलना चाहूंगा।

क्या प्रत्येक आदेश के परिणाम को स्पष्ट रूप से जांचे बिना यह संभव है?

जैसे

dosomething1
if [[ $? -ne 0 ]]; then
    exit 1
fi

dosomething2
if [[ $? -ne 0 ]]; then
    exit 1
fi

8
इसके अलावा set -e, भी set -u(या set -eu) करें। -uमुहावरेदार, बग-छिपने वाले व्यवहार को समाप्त करता है जिसे आप किसी भी गैर-परिवर्तनीय चर तक पहुंच सकते हैं और कोई निदान के साथ उत्पादित खाली मान हो सकता है।
काज

जवाबों:


742

इसे स्क्रिप्ट की शुरुआत में जोड़ें:

set -e

यह शेल तुरंत बाहर निकलने का कारण बनेगा यदि एक साधारण कमांड नॉनजरो एग्जिट वैल्यू के साथ बाहर निकलता है। एक साधारण कमांड किसी भी कमांड का एक हिस्सा नहीं है, जबकि, या जब तक परीक्षण, या a && या का हिस्सा नहीं है || सूची।

देखें बैश (1) आदमी पेज अधिक जानकारी के लिए "सेट" आंतरिक आदेश पर।

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


36
यह काम करेगा, लेकिन मुझे "#! / Usr / bin / env bash" का उपयोग करना पसंद है क्योंकि मैं अक्सर / बिन के अलावा कहीं से भी बैश चलाता हूं। और "#! / Usr / bin / env bash -e" काम नहीं करता है। इसके अलावा, जब मैं डिबगिंग के लिए ट्रेसिंग चालू करना चाहता हूं, तो "सेट -xe" को पढ़ने के लिए संशोधित करने के लिए एक जगह होना अच्छा है।
विले लॉरिकारी

48
इसके अलावा, यदि पटकथा के रूप में चलाया जाता है, तो शेबंग लाइन पर झंडे को अनदेखा किया जाता है bash script.sh
टॉम एंडरसन

27
बस एक नोट: यदि आप बैश स्क्रिप्ट के अंदर फ़ंक्शन की घोषणा करते हैं, तो फ़ंक्शन को फ़ंक्शन बॉडी के अंदर सेट-रीड रिक्लेयर करना होगा यदि आप इस कार्यक्षमता को बढ़ाना चाहते हैं।
जिन किम

8
इसके अलावा, यदि आप अपनी स्क्रिप्ट का स्रोत बनाते हैं, तो शेबबैंग लाइन अप्रासंगिक हो जाएगी।

4
@ जीनकिम 3.2.48 के मामले में दिखाई नहीं देता है। एक स्क्रिप्ट के अंदर निम्नलिखित प्रयास करें set -e; tf() { false; }; tf; echo 'still here':। यहां तक ​​कि set -eशरीर के अंदर के बिना tf(), निष्पादन समाप्त हो गया है। शायद आपका कहने का मतलब यह set -eहै कि यह सबहेल्डों को विरासत में नहीं मिला है , जो कि सच है।
mklement0

202

स्वीकृत उत्तर में जोड़ने के लिए:

ध्यान रखें कि set -eकभी-कभी पर्याप्त नहीं होता है, खासकर यदि आपके पास पाइप हैं।

उदाहरण के लिए, मान लीजिए कि आपके पास यह स्क्रिप्ट है

#!/bin/bash
set -e 
./configure  > configure.log
make

... जो उम्मीद के configureमुताबिक काम करता है: निष्पादन में त्रुटि ।

कल आप एक उचित परिवर्तन करते हैं:

#!/bin/bash
set -e 
./configure  | tee configure.log
make

... और अब यह काम नहीं करता। यह यहाँ समझाया गया है , और एक समाधान (केवल बाश) प्रदान किया गया है:

#! / Bin / bash
सेट 
set -o pipefail

./configure | टी कॉन्फ़िगर करें
बनाना

1
pipefailसाथ जाने के महत्व को समझाने के लिए धन्यवाद set -o!
माल्कॉम

83

यदि आपके उदाहरण में कथन अनावश्यक हैं। बस इसे इस तरह से करें:

dosomething1 || exit 1

यदि आप विले लॉरिकारी की सलाह लेते हैं और उपयोग करते हैं set -eतो कुछ कमांड के लिए आपको इसका उपयोग करने की आवश्यकता हो सकती है:

dosomething || true

|| trueकर देगा आदेश पाइपलाइन एक है trueवापसी मान भले ही आदेश में विफल रहता है तो -eविकल्प स्क्रिप्ट नहीं मारूंगा।


1
यह मुझे पंसद है। विशेष रूप से क्योंकि शीर्ष उत्तर बैश-केंद्रित है (मेरे लिए बिल्कुल स्पष्ट नहीं है कि क्या / किस हद तक यह zsh स्क्रिप्टिंग पर लागू होता है)। और मैं इसे देख सकता था, लेकिन आपका तर्क स्पष्ट है, क्योंकि तर्क।
g33kz0r

set -eबैश-केंद्रित नहीं है - यह मूल बॉर्न शेल पर भी समर्थित है।
मार्कोस विल्स डेल सोल

27

यदि आपके पास सफाई है, तो आपको बाहर निकलने की आवश्यकता है, तो आप छद्म संकेत ईआरआर के साथ 'ट्रैप' का भी उपयोग कर सकते हैं। यह उसी तरह से काम करता है जैसे कि INT या किसी अन्य सिग्नल को फंसाने के लिए; यदि कोई कमांड नॉनज़रो वैल्यू से बाहर निकलती है तो ईआरआर को बैश करें:

# Create the trap with   
#    trap COMMAND SIGNAME [SIGNAME2 SIGNAME3...]
trap "rm -f /tmp/$MYTMPFILE; exit 1" ERR INT TERM
command1
command2
command3
# Partially turn off the trap.
trap - ERR
# Now a control-C will still cause cleanup, but
# a nonzero exit code won't:
ps aux | grep blahblahblah

या, खासकर यदि आप "सेट-ई" का उपयोग कर रहे हैं, तो आप बाहर निकल सकते हैं; आपके जाल को तब निष्पादित किया जाएगा जब स्क्रिप्ट किसी भी कारण से बाहर निकलती है, जिसमें एक सामान्य अंत शामिल है, बाधित होता है, -ई विकल्प के कारण बाहर निकलता है, आदि।


12

$?चर शायद ही कभी की जरूरत है। छद्म मुहावरे command; if [ $? -eq 0 ]; then X; fiको हमेशा लिखा जाना चाहिए if command; then X; fi

जिन मामलों $?में आवश्यकता होती है, जब उन्हें कई मूल्यों के खिलाफ जांचने की आवश्यकता होती है:

command
case $? in
  (0) X;;
  (1) Y;;
  (2) Z;;
esac

या जब $?पुन: उपयोग या अन्यथा हेरफेर करने की आवश्यकता हो:

if command; then
  echo "command successful" >&2
else
  ret=$?
  echo "command failed with exit code $ret" >&2
  exit $ret
fi

3
क्यों "हमेशा के रूप में लिखा जाना चाहिए"? मेरा मतलब है, क्यों "ऐसा " होना चाहिए ? जब एक कमांड लंबी होती है (एक दर्जन विकल्पों के साथ जीसीसी को लागू करने के बारे में सोचें), तो रिटर्न की स्थिति की जांच करने से पहले कमांड चलाना बहुत अधिक पठनीय है।
ysap

यदि कोई आदेश बहुत लंबा है, तो आप इसे नामकरण (शेल फ़ंक्शन को परिभाषित) करके तोड़ सकते हैं।
मार्क एडगर

12

इसके साथ -eया set -eशीर्ष पर चलाएँ ।

इसके अलावा को देखो set -u


34
संभावित रूप से दूसरों को पढ़ने की आवश्यकता को बचाने के लिए help set: -uत्रुटियों के रूप में परेशान चर के संदर्भों का व्यवहार करता है।
mklement0

1
तो यह set -uया तो है set -e, दोनों नहीं है? @lumpynose
जुआन

1
@रिक मैं कई साल पहले सेवानिवृत्त हुआ। भले ही मैं अपने काम से प्यार करता था लेकिन मेरा वृद्ध मस्तिष्क सब कुछ भूल गया है। ऑफहैंड मुझे लगता है कि आप दोनों का एक साथ उपयोग कर सकते हैं; मेरी ओर से बुरा वचन; मुझे "और / या" कहना चाहिए था।
lumpynose

3

एक अभिव्यक्ति की तरह

dosomething1 && dosomething2 && dosomething3

जब कोई कमांड नॉन-जीरो वैल्यू के साथ लौटेगी तो प्रोसेसिंग बंद हो जाएगी। उदाहरण के लिए, निम्नलिखित कमांड कभी भी "किया" नहीं जाएगा:

cat nosuchfile && echo "done"
echo $?
1


-2

मार्क एडगर्स इनपुट के लिए एक अतिरिक्त प्रश्न था क्योंकि यहां संदर्भ के लिए एक और एक में फेंक रहा है और यहां एक अतिरिक्त उदाहरण है और समग्र विषय पर छूता है:

[[ `cmd` ]] && echo success_else_silence

जैसा cmd || exit errcodeकि किसी ने दिखाया वैसा ही है ।

जैसे। मैं यह सुनिश्चित करना चाहता हूं कि यदि माउंटेड है तो एक पार्टीशन अनमाउंट है:

[[ `mount | grep /dev/sda1` ]] && umount /dev/sda1 

5
नहीं, [[ cmd`]] `एक ही बात नहीं है। यदि कमांड का आउटपुट स्थिति से बाहर है, तो यह गलत है, अन्यथा कमांड का आउटपुट खाली और सही है।
गाइल्स का SO- बुराई पर रोक '
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.