बैश स्क्रिप्ट में, अगर कोई निश्चित स्थिति होती है, तो मैं पूरी स्क्रिप्ट से कैसे बाहर निकल सकता हूँ?


717

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

वहाँ एक तरीका है कि मैं पूरी स्क्रिप्ट को थोड़ी देर के लूप के अंदर लपेटकर और ब्रेक का उपयोग किए बिना कर सकता हूं? डन डन डन गोटो जैसा कुछ ?

जवाबों:


808

इस कथन को आज़माएँ:

exit 1

1उपयुक्त त्रुटि कोड के साथ बदलें । विशेष अर्थ के साथ बाहर निकलें कोड भी देखें ।


4
@CMCDragonkai, आमतौर पर कोई भी गैर-शून्य कोड काम करेगा। यदि आपको कुछ विशेष की आवश्यकता नहीं है, तो आप बस 1लगातार उपयोग कर सकते हैं । यदि स्क्रिप्ट का अर्थ किसी अन्य स्क्रिप्ट द्वारा चलाया जाना है, तो आप विशेष अर्थ के साथ अपने स्वयं के स्टेटस कोड को निर्धारित करना चाह सकते हैं। उदाहरण के लिए, 1== परीक्षण विफल, 2== संकलन विफल रहा। यदि स्क्रिप्ट कुछ और का हिस्सा है, तो आपको वहां इस्तेमाल की जाने वाली प्रथाओं से मेल खाने के लिए कोड को समायोजित करने की आवश्यकता हो सकती है। उदाहरण के लिए, जब परीक्षण सूट का हिस्सा ऑटोमेक द्वारा चलाया जाता है, तो कोड 77का उपयोग एक परीक्षण को चिह्नित करने के लिए किया जाता है।
मिशेल गोरी

21
नहीं, यह भी खिड़की बंद कर देता है, न सिर्फ स्क्रिप्ट से बाहर
Toni Leigh

7
@ToniLeigh bash में "विंडो" की अवधारणा नहीं है, आप शायद इस बात को लेकर भ्रमित हैं कि आपका विशेष सेट-अप - जैसे टर्मिनल एमुलेटर - क्या करता है।
माइकल फौकरीस

3
@ToniLeigh यदि यह "विंडो" बंद कर रहा है, तो संभावना है कि आप exit #कमांड को फंक्शन के अंदर रख रहे हैं , स्क्रिप्ट के नहीं। (जिसके return #बजाय मामले में उपयोग करें ।)
जेमी

1
@ सीनियरहाट्स 0 का मतलब है कि यह सफल रहा, इस प्रकार exit 0स्क्रिप्ट से बाहर निकलें और 0 (अन्य स्क्रिप्ट बता रहे हैं जो इस स्क्रिप्ट के सफल होने के परिणाम का उपयोग कर सकते हैं)
विक्टरगैलिसन

689

सेट -e का उपयोग करें

#!/bin/bash

set -e

/bin/command-that-fails
/bin/command-that-fails2

पहली पंक्ति के विफल होने के बाद स्क्रिप्ट समाप्त हो जाएगी (नॉनज़ेरो एग्जिट कोड लौटाता है)। इस स्थिति में, कमांड-कि-फेल 2 नहीं चलेगा।

यदि आप हर एक कमांड के रिटर्न स्टेटस की जांच करते हैं, तो आपकी स्क्रिप्ट इस तरह दिखाई देगी:

#!/bin/bash

# I'm assuming you're using make

cd /project-dir
make
if [[ $? -ne 0 ]] ; then
    exit 1
fi

cd /project-dir2
make
if [[ $? -ne 0 ]] ; then
    exit 1
fi

सेट के साथ - यह ऐसा दिखेगा:

#!/bin/bash

set -e

cd /project-dir
make

cd /project-dir2
make

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


10
साथ set -eतुम अब भी कर सकते हैं बनाने के कुछ स्क्रिप्ट रोकने के बिना त्रुटियों के साथ आदेशों से बाहर निकलें: command 2>&1 || echo $?
Adobe

6
set -eयदि कोई पाइपलाइन या कमांड संरचना गैर-शून्य मान देता है, तो स्क्रिप्ट को रद्द कर देगा। उदाहरण के लिए foo || bar, केवल तभी विफल होगा जब दोनों fooऔर barशून्य-शून्य मान लौटाएँ। यदि आप set -eशुरुआत में जोड़ते हैं तो आमतौर पर एक अच्छी तरह से लिखी गई बैश स्क्रिप्ट काम करेगी और इसके अलावा एक स्वचालित पवित्रता जांच के रूप में काम करती है: यदि कुछ भी गलत हुआ तो स्क्रिप्ट को रद्द कर दें।
मिकको रेंटालिनेन

6
यदि आप एक साथ कमांड पाइप कर रहे हैं, तो आप भी असफल हो सकते हैं यदि उनमें से कोई भी set -o pipefailविकल्प सेट करके विफल हो जाता है ।
जेक बिसिंगर

18
वास्तव में इसके बिना मुहावरेदार कोड set -eसिर्फ होगा make || exit $?
ट्रिपल

4
आपके पास भी है set -u। करने के लिए एक नजर डालें अनौपचारिक बैश सख्त मोड : set -euo pipefail
पाब्लो ए

235

एक SysOps आदमी ने एक बार मुझे तीन पंजे वाली पंजा तकनीक सिखाई:

yell() { echo "$0: $*" >&2; }
die() { yell "$*"; exit 111; }
try() { "$@" || die "cannot $*"; }

ये कार्य * NIX OS और शेल फ्लेवर-मजबूत हैं। उन्हें अपनी स्क्रिप्ट (बैश या अन्यथा), try()अपने बयान और कोड की शुरुआत में रखें ।

व्याख्या

( उड़ती भेड़ टिप्पणी पर आधारित )।

  • yell: स्क्रिप्ट नाम और सभी तर्क मुद्रित करें stderr:
    • $0 स्क्रिप्ट का रास्ता है;
    • $* सभी तर्क हैं।
    • >&2का अर्थ >है & rdout को अनुप्रेषित करना & पाइप2पाइप1stdout ही होगा ।
  • dieके रूप में ही करता है yell, लेकिन एक गैर 0 बाहर निकलने की स्थिति के साथ बाहर निकलता है , जिसका अर्थ है "विफल"।
  • try||(बूलियन OR) का उपयोग करता है , जो केवल बाईं ओर विफल होने पर सही पक्ष का मूल्यांकन करता है।
    • $@फिर से सभी तर्क हैं, लेकिन अलग

3
मैं यूनिक्स स्क्रिप्टिंग के लिए काफी नया हूं। क्या आप बता सकते हैं कि उपरोक्त कार्यों को कैसे निष्पादित किया जाता है? मैं कुछ नए वाक्यविन्यास देख रहा हूं जिनसे मैं परिचित नहीं हूं। धन्यवाद।
काइज़ेनकोडर

15
yell : $0स्क्रिप्ट का मार्ग है। $*सभी तर्क हैं। >&2का अर्थ है " पाइप पर >रीडायरेक्ट पुनर्निर्देशन "। पाइप 1 खुद ही stdout होगा। इसलिए चिल्लाना स्क्रिप्ट नाम के साथ सभी तर्कों को उपसर्ग करता है और स्टाडर को प्रिंट करता है। मरना येल के समान होता है , लेकिन गैर-0 से बाहर निकलने की स्थिति के साथ बाहर निकलता है, जिसका अर्थ है "असफल"। बूलियन का उपयोग करने का प्रयास करें या , जो केवल दाईं ओर का मूल्यांकन करता है यदि बाईं ओर विफल नहीं हुआ। फिर से सभी तर्क हैं, लेकिन अलग । उम्मीद है कि सब कुछ बताते हैं&2||$@
उड़ान भेड़

1
मैंने इसे संशोधित किया die() { yell "$1"; exit $2; }ताकि आप एक संदेश और बाहर निकलने के कोड के साथ पास कर सकें die "divide by zero" 115
मार्क लकाटा

3
मैं देख सकता हूँ कि मैं कैसे उपयोग yellऔर उपयोग करूँगा die। हालांकि, tryइतना नहीं। क्या आप इसका उपयोग करने का एक उदाहरण प्रदान कर सकते हैं?
kshenoy

2
हम्म, लेकिन आप उन्हें एक स्क्रिप्ट में कैसे उपयोग करते हैं? मुझे समझ में नहीं आ रहा है कि आप "अपने बयान और कोड पर" (कोशिश) का क्या मतलब है।
दजवायु-इवान मिलोसावलजेवि

33

यदि आप स्क्रिप्ट को इनवॉइस करेंगे source, तो आप उपयोग कर सकते हैं return <x>जहां <x>स्क्रिप्ट निकास स्थिति होगी (त्रुटि या गलत के लिए गैर-शून्य मान का उपयोग करें)। लेकिन यदि आप एक निष्पादन योग्य स्क्रिप्ट (यानी, सीधे उसके फ़ाइलनाम के साथ) का आह्वान करते हैं, तो रिटर्न स्टेटमेंट का परिणाम एक शिकायत (त्रुटि संदेश "रिटर्न: केवल एक फ़ंक्शन या स्रोत से स्क्रिप्ट में 'वापसी') हो सकता है।

यदि exit <x>इसके बजाय इसका उपयोग किया जाता है, तो जब स्क्रिप्ट को लागू किया जाता है, तो यह स्क्रिप्ट को sourceशुरू करने वाले शेल से बाहर निकलने के परिणामस्वरूप होगा, लेकिन एक निष्पादन योग्य स्क्रिप्ट उम्मीद के मुताबिक समाप्त हो जाएगी।

एक ही स्क्रिप्ट में किसी भी मामले को संभालने के लिए, आप उपयोग कर सकते हैं

return <x> 2> /dev/null || exit <x>

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

नोट: <x>यह केवल एक संख्या माना जाता है।


किसी फंक्शन के अंदर रिटर्न / एग्जिट वाली स्क्रिप्ट में मेरे लिए काम नहीं करता है, यानी बिना शेल के मौजूदा फंक्शन के अंदर बाहर निकलना संभव है, लेकिन फंक्शन के रिटर्न कोड की सही जांच के लिए फंक्शन कॉलर केयर बनाए बिना ?
jan

@jan रिटर्न मानों के साथ कॉलर क्या करता है (या नहीं करता है), पूरी तरह से ऑर्थोगोनल (यानी, स्वतंत्र) है कि आप फ़ंक्शन से कैसे लौटते हैं (... w / o शेल से बाहर निकल रहे हैं, चाहे कोई भी आह्वान हो)। यह मुख्य रूप से कॉलर कोड पर निर्भर करता है, जो इस प्रश्नोत्तर का हिस्सा नहीं है। तुम भी फोन करने वाले की जरूरतों के लिए समारोह के वापसी मूल्य दर्जी कर सकते हैं, लेकिन यह जवाब सीमा नहीं है कि यह वापसी मूल्य क्या हो सकता है ...
kavadias

11

मैं अक्सर त्रुटियों को संभालने के लिए रन () नामक एक फ़ंक्शन शामिल करता हूं। मेरे द्वारा किए जाने वाले प्रत्येक कॉल को इस फ़ंक्शन पर भेज दिया जाता है, इसलिए विफलता के हिट होने पर पूरी स्क्रिप्ट बाहर निकल जाती है। सेट-सॉल्यूशन के ऊपर इसका लाभ यह है कि जब कोई लाइन विफल होती है तो स्क्रिप्ट चुपचाप बाहर नहीं निकलती है, और आपको बता सकती है कि समस्या क्या है। निम्नलिखित उदाहरण में, तीसरी पंक्ति निष्पादित नहीं की जाती है क्योंकि स्क्रिप्ट कॉल पर झूठी से बाहर निकल जाती है।

function run() {
  cmd_output=$(eval $1)
  return_value=$?
  if [ $return_value != 0 ]; then
    echo "Command $1 failed"
    exit -1
  else
    echo "output: $cmd_output"
    echo "Command succeeded."
  fi
  return $return_value
}
run "date"
run "false"
run "date"

1
यार, किसी कारण से, मैं वास्तव में इस जवाब को पसंद करता हूं। मुझे लगता है कि यह थोड़ा अधिक जटिल है, लेकिन यह इतना उपयोगी लगता है। और यह देखते हुए कि मैं कोई बैश विशेषज्ञ नहीं हूं, यह मुझे विश्वास दिलाता है कि मेरा तर्क दोषपूर्ण है, और इस पद्धति में कुछ गड़बड़ है, अन्यथा, मुझे लगता है कि दूसरों ने इसे अधिक प्रशंसा दी होगी। तो, इस समारोह में क्या समस्या है? क्या कुछ ऐसा है जिसे मुझे यहाँ देखना चाहिए?

मुझे eval का उपयोग करने के लिए मेरा कारण याद नहीं है, फ़ंक्शन cmd_output = $ ($ 1) के साथ ठीक काम करता है
जोसेफ शीडी

मैंने इसे एक जटिल तैनाती प्रक्रिया के हिस्से के रूप में लागू किया और इसने शानदार काम किया। धन्यवाद और यहाँ एक टिप्पणी और एक टिप्पणी है।
फज़्यग्रुप

सचमुच अद्भुत काम! यह सबसे सरल और साफ समाधान है जो अच्छी तरह से काम करता है। मेरे लिए मैंने इसे एक लूप में एक कमांड से पहले जोड़ा था क्योंकि फॉर लूप्स नहीं उठाएगा set -e option। फिर कमांड, चूंकि यह तर्क के साथ है, इसलिए मैंने बैश मुद्दों से बचने के लिए एकल उद्धरणों का उपयोग किया runTry 'mysqldump $DB_PASS --user="$DB_USER" --host="$BV_DB_HOST" --triggers --routines --events --single-transaction --verbose $DB_SCHEMA $tables -r $BACKUP_DIR/$tables$BACKUP_FILE_NAME'। नोट: मैंने फ़ंक्शन का नाम रनट्री में बदल दिया है।
टोनी-कैफ

1
evalसंभावित रूप से खतरनाक है यदि आप मनमाना इनपुट स्वीकार करते हैं, लेकिन अन्यथा यह बहुत अच्छा लगता है।
ड्रैगन 88

5

ifनिर्माण के बजाय , आप शॉर्ट-सर्किट मूल्यांकन का लाभ उठा सकते हैं :

#!/usr/bin/env bash

echo $[1+1]
echo $[2/0]              # division by 0 but execution of script proceeds
echo $[3+1]
(echo $[4/0]) || exit $? # script halted with code 1 returned from `echo`
echo $[5+1]

कोष्ठक की जोड़ी पर ध्यान दें जो वैकल्पिक संचालक की प्राथमिकता के कारण आवश्यक है। $?हाल ही में कहे गए कमांड के कोड से बाहर निकलने के लिए एक विशेष चर सेट है।


1
अगर मैं command -that --fails || exit $?इसे बिना कोष्ठक के काम करता हूं, तो ऐसा क्या है जिसके echo $[4/0]कारण हमें इनकी आवश्यकता है?
एंथ्रोपिक

2
@Anentropic @skalee कोष्ठक का पूर्वता से कोई लेना-देना नहीं है, लेकिन अपवाद से निपटने के लिए। डिवाइड-बाय-ज़ीरो कोड 1 के साथ शेल से तत्काल बाहर निकलने का कारण होगा। बिना कोष्ठक (यानी, एक साधारण echo $[4/0] || exit $?) बैश कभी भी निष्पादित नहीं करेगा echo, अकेले आज्ञा मानें ||
बॉबबोगो

1

मेरे पास एक ही सवाल है, लेकिन यह नहीं पूछ सकता क्योंकि यह एक डुप्लिकेट होगा।

एक्सेप्ट का उपयोग करते हुए स्वीकृत उत्तर, स्क्रिप्ट के अधिक जटिल होने पर काम नहीं करता है। यदि आप स्थिति की जांच करने के लिए पृष्ठभूमि प्रक्रिया का उपयोग करते हैं, तो केवल उस प्रक्रिया से बाहर निकलें, क्योंकि यह उप-शेल में चलता है। स्क्रिप्ट को मारने के लिए, आपको इसे स्पष्ट रूप से मारना होगा (कम से कम यह एकमात्र तरीका है जो मुझे पता है)।

यहाँ कैसे करना है पर एक छोटी सी स्क्रिप्ट है:

#!/bin/bash

boom() {
    while true; do sleep 1.2; echo boom; done
}

f() {
    echo Hello
    N=0
    while
        ((N++ <10))
    do
        sleep 1
        echo $N
        #        ((N > 5)) && exit 4 # does not work
        ((N > 5)) && { kill -9 $$; exit 5; } # works 
    done
}

boom &
f &

while true; do sleep 0.5; echo beep; done

यह एक बेहतर जवाब है, लेकिन अभी भी अधूरा है मैं वास्तव में नहीं जानता कि कैसे बूम भाग से छुटकारा पाएं ।

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