नेस्टेड छोरों के साथ एक शेल स्क्रिप्ट से बाहर निकलना


11

मेरे पास नेस्टेड छोरों के साथ एक शेल स्क्रिप्ट है और बस पता चला है कि "निकास" वास्तव में स्क्रिप्ट से बाहर नहीं निकलता है, लेकिन केवल वर्तमान लूप है। क्या एक निश्चित त्रुटि स्थिति पर स्क्रिप्ट से पूरी तरह से बाहर निकलने का एक और तरीका है?

मैं "सेट-ई" का उपयोग नहीं करना चाहता, क्योंकि स्वीकार्य त्रुटियां हैं और इसके लिए बहुत अधिक पुनर्लेखन की आवश्यकता होगी।

अभी, मैं मैन्युअल रूप से प्रक्रिया को मारने के लिए किल का उपयोग कर रहा हूं, लेकिन ऐसा लगता है कि ऐसा करने का एक बेहतर तरीका होना चाहिए।


1
आपका क्या मतलब है कि "निकास" वास्तव में स्क्रिप्ट से बाहर नहीं निकलता है? यह करता है, बस कोशिश करो bash -c 'for x in y z; do exit; done; echo "This never gets printed"'
क्रिस डाउन

आप सही हैं, यह आमतौर पर नेस्टेड छोरों से बाहर निकलना चाहिए, लेकिन जब मैं बाहर निकलने का उपयोग करता हूं तो मेरी स्क्रिप्ट बाहरी लूप के साथ जारी रहती है। मैं स्क्रिप्ट पोस्ट नहीं कर सकता।
user923487

2
आप एक स्क्रिप्ट क्यों नहीं लिख सकते हैं जो समस्या को दिखाती है और इसे यहां पोस्ट करती है? यह मेरी संभावना नहीं है।
टोबी स्पाइट

1
क्या यह मामला है कि आंतरिक लूप आपके कोड में एक उप-शेल में होता है?
टोबी स्पाइट

@ टॉबी अधिकांश स्क्रिप्ट लॉगिंग उद्देश्यों के लिए एक उप शेल में है, लेकिन लूप और कोड के बाकी दोनों समान उप शेल में हैं।
user923487

जवाबों:


19

आपकी समस्या नेस्टेड छोरों नहीं है, प्रति से। यह है कि आपके आंतरिक छोरों में से एक या अधिक उप-भाग में चल रहा है

यह काम:

#!/bin/bash

for i in $(seq 1 100); do
        echo i $i
        for j in $(seq 1 10) ; do
                echo j $j
                sleep 1
                [[ $j = 3 ]] && { echo "I've had enough!" 1>&2; exit 1; }
        done
        echo "After the j loop."
done
echo "After all the loops."

उत्पादन:

i 1
j 1
j 2
j 3
I've had enough!

यह आपके द्वारा वर्णित समस्या को प्रस्तुत करता है:

#!/bin/bash

for i in $(seq 1 100); do
        echo i $i
        cat /etc/passwd | while read line; do
                echo LINE $line
                sleep 1
                [[ "$line" = "daemon:x:2:2:daemon:/sbin:/sbin/nologin" ]] && { echo "I've had enough!" 1>&2; exit 1; }
        done
        echo "After the j loop."
done    
echo "After all the loops."

उत्पादन:

i 1
LINE root:x:0:0:root:/root:/bin/bash
LINE bin:x:1:1:bin:/bin:/sbin/nologin
LINE daemon:x:2:2:daemon:/sbin:/sbin/nologin
I've had enough!
After the j loop.
i 2
LINE root:x:0:0:root:/root:/bin/bash
LINE bin:x:1:1:bin:/bin:/sbin/nologin
LINE daemon:x:2:2:daemon:/sbin:/sbin/nologin
I've had enough!
After the j loop.
i 3
LINE root:x:0:0:root:/root:/bin/bash
(...etc...)

यहाँ समाधान है; आपको इनर लूप के रिटर्न वैल्यू का परीक्षण करना होगा जो सबहेल में चलते हैं:

#!/bin/bash

for i in $(seq 1 100); do
        echo i $i
        cat /etc/passwd | while read line; do
                echo LINE $line
                sleep 1
                [[ "$line" = "daemon:x:2:2:daemon:/sbin:/sbin/nologin" ]] && { echo "I've had enough!" 1>&2; exit 1; }
        done
        err=$?; [[ $err != 0 ]] && exit $err
        echo "After the j loop."
done
echo "After all the loops."

परीक्षण पर ध्यान दें: [[ $? != 0 ]] && exit $?

उत्पादन:

i 1
LINE root:x:0:0:root:/root:/bin/bash
LINE bin:x:1:1:bin:/bin:/sbin/nologin
LINE daemon:x:2:2:daemon:/sbin:/sbin/nologin
I've had enough!

संपादित करें: आप किस उपधारा में हैं, यह सत्यापित करने के लिए, "उत्तर" स्क्रिप्ट को संशोधित करके बताएं कि आपके वर्तमान शेल की प्रक्रिया आईडी क्या है। नोट: यह केवल बाश 4 में काम करता है:

#!/bin/bash

for i in $(seq 1 100); do
        echo pid $BASHPID i $i
        cat /etc/passwd | while read line; do
                echo pid $BASHPID LINE $line
                sleep 1
                [[ "$line" = "daemon:x:2:2:daemon:/sbin:/sbin/nologin" ]] && { echo "I've had enough!" 1>&2; exit 1; }
        done
        err=$?; [[ $err != 0 ]] && echo pid $BASHPID && exit $err
        echo "After the j loop."
done
echo "After all the loops."

उत्पादन:

pid 31793 i 1
pid 31796 LINE root:x:0:0:root:/root:/bin/bash
pid 31796 LINE bin:x:1:1:bin:/bin:/sbin/nologin
pid 31796 LINE daemon:x:2:2:daemon:/sbin:/sbin/nologin
I've had enough!
pid 31793

चर "i" और "j" आपको फोरट्रान के सौजन्य से लाया गया। आपका दिन शुभ हो। :-)


दोनों आंतरिक और बाहरी लूप एक ही उप शेल में चल रहे हैं, इसलिए भीतर से बाहर निकलना दोनों से बाहर निकलना चाहिए? हालांकि मुझे समस्या को स्वयं हल करने में परेशानी होती है। जैसे ही मैं प्रोग्राम लॉजिक को हटाता हूं, समस्या दूर हो जाती है। वैसे भी, मैं इसे अभी के लिए उत्तर के रूप में चिह्नित करूंगा, क्योंकि इसके साथ कुछ करने की संभावना है।
user923487

आपके द्वारा दिए गए लिंक को पढ़ने के बाद, मुझे लगता है कि मुझे समस्या मिल गई है। बाहरी लूप में मैं "कैट फाइल | रीड लाइन के दौरान" कर रहा हूं। पाइपिंग एक उप शेल बनाता है। मुझे नहीं पता था।
user923487

@ user923487 - मेरा अद्यतन उत्तर देखें। यदि आपके पास 4 बैश है, तो आप सब-पैड को गूंज सकते हैं (या प्रिंटफ, यदि आप आधुनिक हैं) सब-पेड को सत्यापित कर सकते हैं और सत्यापित कर सकते हैं कि आप सब्स्क्रिप्शन में हैं या नहीं। अपना बैश संस्करण देखने के लिए, bash --versionकमांड लाइन पर टाइप करें।
माइक एस।

बहुत मददगार। धन्यवाद! हालांकि मुझे यह कहना पड़ा "इसे मार डालो scriptname.sh" इसे हल करने का सबसे सीधा तरीका लगता है।
user923487

2

एक पहले जवाब उपयोग करने का सुझाव [[ $? != 0 ]] && exit $?लेकिन यह नहीं होगा काफी उम्मीद के रूप में काम करते हैं, क्योंकि [[ $? != 0 ]]परीक्षण रीसेट कर देगा $?, शून्य करने के लिए वापस जिसका अर्थ है कि हालांकि स्क्रिप्ट होगा जल्दी बाहर निकलने की उम्मीद के रूप में, यह हमेशा हूँ कोड 0 के साथ बाहर निकलें (उम्मीद नहीं के रूप में) । साथ ही, स्ट्रिंग तुलना परीक्षण के -neबजाय संख्यात्मक तुलना परीक्षण का उपयोग करना बेहतर होगा !=। इसलिए IMHO उपयोग करने के लिए एक बेहतर उपाय है:

err=$?; [[ $err -ne 0 ]] && exit $err

जैसा कि यह सुनिश्चित करेगा कि वास्तविक निकास कोड सही ढंग से सेट है।


अच्छी प्रतिक्रिया। मैंने कोड ठीक कर दिया है।
माइक एस

1

आप उपयोग कर सकते हैं break

से help break:

Exit a FOR, WHILE or UNTIL loop.  If N is specified, break N enclosing loops.

तो तीन एनक्लोजिंग लूप्स से बाहर निकलने के लिए अर्थात यदि आपके पास मुख्य के अंदर दो नेस्टेड लूप हैं, तो इन सभी में से बाहर निकलने के लिए इसका उपयोग करें:

break 3

छोरों के बाद अधिक कोड है, इसलिए अकेले उन लोगों को तोड़ना पर्याप्त नहीं है।
user923487

1
शांत thx! उदाहरणfor((i=0;i<3;i++));do echo A;for((j=0;j<2;j++));do echo B;break 2;done;done
कुंभ राशि बिजली

0

exit पूरे शेल या वर्तमान उप-शेल को समाप्त करता है:

$ bash -c 'for i in 1 2 3; do for j in 4 5 6; do echo $i; exit 1; echo $j; done; done'
1
$ echo $?
1
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.