प्रक्रिया समाप्त होने पर डिफ़ॉल्ट निकास कोड?


54

एक प्रक्रिया की तरह एक हैंडल करने योग्य संकेत के साथ मार दिया जाता है जब SIGINTया SIGTERM, लेकिन यह संकेत संभाल नहीं करता है, क्या प्रक्रिया के निकास कोड होगा?

जैसे अनहेल्दी-सक्षम संकेतों के बारे में क्या SIGKILL?

मैं जो बता सकता हूं, एक प्रक्रिया को SIGINTएक्जिट कोड में परिणाम के साथ मारना 130, लेकिन क्या यह कर्नेल या शेल कार्यान्वयन से भिन्न होगा?

$ cat myScript
#!/bin/bash
sleep 5
$ ./myScript
<ctrl-c here>
$ echo $?
130

मुझे यकीन नहीं है कि मैं अन्य संकेतों का परीक्षण कैसे करूंगा ...

$ ./myScript &
$ killall myScript
$ echo $?
0  # duh, that's the exit code of killall
$ killall -9 myScript
$ echo $?
0  # same problem

1
आपके killall myScriptकाम करता है, इसलिए हत्यारे की वापसी (और स्क्रिप्ट का नहीं!) है 0. आप एक kill -x $$[x सिग्नल संख्या होने के नाते रख सकते हैं , और $$ आमतौर पर उस स्क्रिप्ट के PID में शेल द्वारा विस्तारित किया जाता है (श, बैश में काम करता है,) ...)] स्क्रिप्ट के अंदर और फिर परीक्षण करें कि इसका निकास कोर क्या था।
ओलिवियर दुलाक


अर्ध-प्रश्न के बारे में टिप्पणी करें: पृष्ठभूमि में myScript मत डालें। (ओमित &)। एक अन्य शेल प्रक्रिया (दूसरे टर्मिनल में) से संकेत भेजें, फिर आप $?myScript समाप्त होने के बाद उपयोग कर सकते हैं ।
मैटबियनको

जवाबों:


61

प्रोसेसर्स अपने माता-पिता के लिए एक एक्जिट कोड की रिपोर्ट करने के लिए पूर्णांक तर्क के साथ _exit()सिस्टम कॉल (लिनक्स पर, यह भी देखें exit_group()) को कॉल कर सकते हैं । यद्यपि यह पूर्णांक है, केवल 8 कम से कम महत्वपूर्ण बिट्स माता-पिता के लिए उपलब्ध हैं (अपवाद है कि जब उस कोड को पुनः प्राप्त करने के लिए माता-पिता में SIGCHLD पर उपयोग waitid()या हैंडलर , हालांकि लिनक्स पर नहीं)।

माता-पिता आमतौर पर एक पूर्णांक के रूप में अपने बच्चे की स्थिति प्राप्त करने के लिए wait()या (हालांकि कुछ अलग शब्दार्थों के रूप में अच्छी तरह से इस्तेमाल किया जा सकता है)।waitpid()waitid()

लिनक्स और अधिकांश यूनियनों पर, यदि प्रक्रिया सामान्य रूप से समाप्त हो जाती है, तो उस स्थिति संख्या के 8 से 15 बिट्स में पास होने के रूप में निकास कोड होगा exit()। यदि नहीं, तो 7 कम से कम महत्वपूर्ण बिट्स (0 से 6) में सिग्नल संख्या होगी और बिट 7 सेट किया जाएगा यदि कोई कोर डंप किया गया था।

perlके $?उदाहरण के लिए कि संख्या से सेट के रूप में शामिल हैं waitpid():

$ perl -e 'system q(kill $$); printf "%04x\n", $?'
000f # killed by signal 15
$ perl -e 'system q(kill -ILL $$); printf "%04x\n", $?'
0084 # killed by signal 4 and core dumped
$ perl -e 'system q(exit $((0xabc))); printf "%04x\n", $?'
bc00 # terminated normally, 0xbc the lowest 8 bits of the status

बॉर्न की तरह के गोले भी अपने $?चर में अंतिम रन कमांड की निकास स्थिति बनाते हैं । हालाँकि, इसमें सीधे तौर पर दी गई संख्या नहीं होती है waitpid(), लेकिन इस पर एक परिवर्तन होता है, और यह गोले के बीच भिन्न होता है।

यदि सभी प्रक्रिया सामान्य रूप से समाप्त हो जाती हैं, तो सभी गोले के बीच सामान्य बात यह है कि $?बाहर निकलने वाले कोड के सबसे कम 8 बिट्स (पास की गई संख्या exit()) शामिल हैं।

जहां यह भिन्न होता है जब सिग्नल द्वारा प्रक्रिया को समाप्त किया जाता है। सभी मामलों में, और यह POSIX द्वारा आवश्यक है, संख्या 128 से अधिक होगी। POSIX निर्दिष्ट नहीं करता है कि मूल्य क्या हो सकता है। हालांकि अभ्यास में, मुझे पता है कि सभी बॉर्न-जैसे गोले में, सबसे कम 7 बिट्स में $?सिग्नल नंबर होगा। लेकिन, nसिग्नल नंबर कहां है,

  • राख में, zsh, pdksh, bash, बॉर्न शेल, $?है 128 + n। इसका मतलब यह है कि उन गोले में, यदि आप एक प्राप्त करते $?हैं 129, तो आप यह नहीं जानते कि क्या यह प्रक्रिया के साथ बाहर निकल गया है exit(129)या क्या यह सिग्नल द्वारा मारा गया था 1( HUPअधिकांश प्रणालियों पर)। लेकिन तर्क यह है कि गोले, जब वे खुद से बाहर निकलते हैं, तो डिफ़ॉल्ट रूप से अंतिम निकास कमांड की निकास स्थिति को वापस करते हैं। यह सुनिश्चित करके कि $?यह 255 से अधिक नहीं है, कि एक सुसंगत निकास स्थिति की अनुमति देता है:

    $ bash -c 'sh -c "kill \$\$"; printf "%x\n" "$?"'
    bash: line 1: 16720 Terminated              sh -c "kill \$\$"
    8f # 128 + 15
    $ bash -c 'sh -c "kill \$\$"; exit'; printf '%x\n' "$?"
    bash: line 1: 16726 Terminated              sh -c "kill \$\$"
    8f # here that 0x8f is from a exit(143) done by bash. Though it's
       # not from a killed process, that does tell us that probably
       # something was killed by a SIGTERM
    
  • ksh93, $?है 256 + n। इसका मतलब है कि $?आप एक मूल्य से एक मारे गए और गैर-मारे गए प्रक्रिया के बीच अंतर कर सकते हैं। kshबाहर निकलने के नए संस्करण , यदि $?255 से अधिक थे , तो अपने माता-पिता को उसी निकास स्थिति की रिपोर्ट करने में सक्षम होने के लिए उसी संकेत के साथ खुद को मारता है। जबकि यह एक अच्छा विचार लगता है, इसका मतलब है कि यदि kshएक अतिरिक्त कोर डंप उत्पन्न होगा (संभावित रूप से एक दूसरे को अधिलेखित करना) अगर प्रक्रिया एक कोर जनरेटिंग सिग्नल द्वारा मार दी गई थी:

    $ ksh -c 'sh -c "kill \$\$"; printf "%x\n" "$?"'
    ksh: 16828: Terminated
    10f # 256 + 15
    $ ksh -c 'sh -c "kill -ILL \$\$"; exit'; printf '%x\n' "$?"
    ksh: 16816: Illegal instruction(coredump)
    Illegal instruction(coredump)
    104 # 256 + 15, ksh did indeed kill itself so as to report the same
        # exit status as sh. Older versions of `ksh93` would have returned
        # 4 instead.
    

    तुम भी कहाँ कह सकते हैं वहाँ एक बग है कि ksh93खुद को मारता है, भले ही $?एक से आता है return 257एक समारोह के द्वारा किया:

    $ ksh -c 'f() { return "$1"; }; f 257; exit'
    zsh: hangup     ksh -c 'f() { return "$1"; }; f 257; exit'
    # ksh kills itself with a SIGHUP so as to report a 257 exit status
    # to its parent
    
  • yashyashएक समझौता प्रदान करता है। यह लौट आता है 256 + 128 + n। इसका मतलब है कि हम एक मारे गए प्रक्रिया और ठीक से समाप्त होने वाले के बीच अंतर कर सकते हैं। और बाहर निकलने पर, यह 128 + nखुद को आत्महत्या किए बिना रिपोर्ट करेगा और इसके दुष्प्रभाव हो सकते हैं।

    $ yash -c 'sh -c "kill \$\$"; printf "%x\n" "$?"'
    18f # 256 + 128 + 15
    $ yash -c 'sh -c "kill \$\$"; exit'; printf '%x\n' "$?"
    8f  # that's from a exit(143), yash was not killed
    

के मूल्य से संकेत प्राप्त करने के लिए $?, पोर्टेबल तरीके का उपयोग करना है kill -l:

$ /bin/kill 0
Terminated
$ kill -l "$?"
TERM

(पोर्टेबिलिटी के लिए, आपको सिग्नल नंबर, केवल सिग्नल के नाम का उपयोग नहीं करना चाहिए)

गैर-बॉर्न मोर्चों पर:

  • csh/ tcshऔर fishबॉर्न शेल के समान है सिवाय इसके कि स्थिति $statusइसके बजाय है $?(ध्यान दें कि अनुकूलता के लिए zshभी सेट करता है ) (इसके अलावा )।$statuscsh$?
  • rc: बाहर निकलने की स्थिति में $statusभी है, लेकिन जब एक संकेत द्वारा मार डाला, उस चर में एक नंबर के बजाय संकेत का नाम होता है (जैसे sigtermया sigill+coreयदि कोई कोर उत्पन्न हुआ था), जो अभी तक उस शेल के अच्छे डिजाइन का एक और सबूत है ।
  • es। बाहर निकलने की स्थिति एक चर नहीं है। यदि आप इसकी देखभाल करते हैं, तो आप कमांड को निम्नानुसार चलाते हैं:

    status = <={cmd}
    

    जो एक नंबर या वापस आ जाएगी sigtermया sigsegv+coreमें की तरह rc

हो सकता है कि पूर्णता के लिए, हमें zsh's' $pipestatusऔर bash's $PIPESTATUSसरणियों का उल्लेख करना चाहिए, जिनमें अंतिम पाइपलाइन के घटकों की निकास स्थिति है।

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

  • bashऔर mksh(R41 के बाद से, एक प्रतिगमन ^ Wchange जाहिरा तौर पर जानबूझकर पेश किया गया) 8 बिट्स (सकारात्मक या नकारात्मक) को छोटा कर देगा। तो उदाहरण के लिए return 1234सेट हो जाएगा $?करने के लिए 210, return -- -1सेट हो जाएगा $?255।
  • zshऔर pdksh(और डेरिवेटिव के अलावा mksh) किसी भी हस्ताक्षर किए गए 32 बिट दशमलव पूर्णांक (-2 31 से 2 31 -1) और (संख्या को 32 बिट तक कम करें ) की अनुमति दें ।
  • ashऔर yash0 से 2 31 -1 तक किसी भी सकारात्मक पूर्णांक की अनुमति दें और उसमें से किसी भी संख्या के लिए एक त्रुटि लौटाएं।
  • ksh93के रूप में सेट return 0करने के लिए है, लेकिन कुछ और के लिए, 8 बिट्स को काटें। जैसा कि पहले ही उल्लेख किया गया है कि 256 और 320 के बीच की संख्या लौटाने से बाहर निकलने पर खुद को मारना पड़ सकता है।return 320$?ksh
  • rcऔर esसूची में से कुछ भी वापस करने की अनुमति दें।

यह भी ध्यान रखें कि कुछ गोले भी की विशेष मूल्यों का उपयोग $?/ $statusकुछ त्रुटि की स्थिति है कि एक प्रक्रिया के निकास की स्थिति, नहीं कर रहे हैं की तरह रिपोर्ट करने के लिए 127या 126के लिए नहीं मिला आदेश या निष्पादन योग्य नहीं (एक स्रोत फ़ाइल में या सिंटेक्स त्रुटि) ...


1
an exit code to their parentऔर to get the *status* of their child। आपने "स्थिति" पर जोर दिया है। है exit codeऔर *status*वही? केस हाँ, दो नाम होने का मूल क्या है? मामला समान नहीं है, क्या आप स्थिति की परिभाषा / संदर्भ दे सकते हैं?
n611x007

2
यहां 3 नंबर हैं। बाहर निकलने के कोड : नंबर करने के लिए पारित कर दिया exit()बाहर निकलने का दर्जा : संख्या से प्राप्त waitpid()जो बाहर निकलने के कोड, संकेत नंबर शामिल हैं और क्या वहाँ था एक कोर फेंक दिया। और संख्या जो कुछ गोले अपने एक विशेष चर ( $?, $status) में उपलब्ध कराती है , जो कि बाहर निकलने की स्थिति का एक प्रकार से रूपांतरण है, जिसमें एक सामान्य समाप्ति होने पर बाहर निकलने का कोड होता है, लेकिन सिग्नल की जानकारी भी देता है प्रक्रिया को मार दिया गया (जिसे आम तौर पर निकास स्थिति भी कहा जाता है )। यह सब मेरे जवाब में समझाया गया है।
स्टीफन चेजलस

1
समझ गया धन्यवाद! मैं निश्चित रूप से यहाँ इस स्पष्ट नोट की सराहना करता हूं। निकास के संबंध में इन अभिव्यक्तियों का उपयोग कुछ स्थानों पर परस्पर विनिमय के लिए किया जाता है। क्या शेल वैरिएबल वेरिएंट का नाम (सामान्य) भी है? इसलिए मैं गोले पर विवरण में जाने से पहले इसे स्पष्ट रूप से स्पष्ट करने का सुझाव दूंगा। मैं आपके पहले या दूसरे पैराग्राफ के बाद स्पष्टीकरण (आपकी टिप्पणी से) सम्मिलित करने का सुझाव दूंगा।
n611x007

1
क्या आप पोसिक्स को इंगित कर सकते हैं जो पहले 7 बिट्स के सिग्नल के बारे में कहता है? सभी मुझे मिल सकता है > 128हिस्सा था : "एक कमांड की निकास स्थिति जो समाप्त हो गई क्योंकि इसे एक संकेत प्राप्त हुआ था, जिसे 128 से अधिक बताया जाएगा।" pubs.opengroup.org/onlinepubs/9699919799/utilities/…
Ciro Santilli 中心 .org .org .org 六四

1
@cuonglm, मुझे नहीं लगता कि यह HTTP पर कहीं और सार्वजनिक रूप से उपलब्ध है, फिर भी आप इसे NNTP पर gmane से प्राप्त कर सकते हैं। संदेश आईडी की तलाश करें efe764d811849b34eef24bfb14106f61@austingroupbugs.net(2015-05-06 से) याXref: news.gmane.org gmane.comp.standards.posix.austin.general:10726
स्टीफन चेज़लस

23

जब कोई प्रक्रिया बाहर निकलती है, तो यह ऑपरेटिंग सिस्टम को पूर्णांक मान लौटाता है। अधिकांश यूनिक्स वेरिएंट पर, इस मान को मोडुलो 256 लिया जाता है: सब कुछ लेकिन कम-ऑर्डर बिट्स को अनदेखा किया जाता है। एक 16-बिट पूर्णांक के माध्यम से एक बच्चे की प्रक्रिया की स्थिति उसके माता-पिता को वापस कर दी जाती है

  • बिट्स 6-6 (7 लो-ऑर्डर बिट्स) सिग्नल संख्या है जो प्रक्रिया को मारने के लिए उपयोग की जाती थी, या यदि प्रक्रिया सामान्य रूप से बाहर निकलती है;
  • बिट 7 सेट है अगर प्रक्रिया एक सिग्नल और डंप किए गए कोर द्वारा मार दी गई थी;
  • यदि प्रक्रिया सामान्य रूप से बाहर निकलती है या प्रक्रिया सिग्नल द्वारा मार दी जाती है तो बिट्स 8-15 प्रक्रिया का निकास कोड है।

स्थिति को waitसिस्टम कॉल या उसके भाई-बहनों में से एक द्वारा लौटाया जाता है । POSIX निकास स्थिति और संकेत संख्या के सटीक एन्कोडिंग को निर्दिष्ट नहीं करता है; यह केवल प्रदान करता है

  • यह बताने का एक तरीका कि बाहर निकलने की स्थिति सिग्नल से मेल खाती है या सामान्य निकास से;
  • निकास कोड तक पहुंचने का एक तरीका, यदि प्रक्रिया सामान्य रूप से बाहर निकलती है;
  • सिग्नल संख्या तक पहुंचने का एक तरीका, यदि प्रक्रिया सिग्नल द्वारा मार दी गई थी।

जब कोई प्रक्रिया सिग्नल द्वारा मार दी जाती है , तो सख्ती से बोलना, कोई निकास कोड नहीं है: इसके बजाय एक निकास स्थिति है

शेल स्क्रिप्ट में, कमांड की निकास स्थिति विशेष चर के माध्यम से रिपोर्ट की जाती है $?। यह चर एक अस्पष्ट तरीके से बाहर निकलने की स्थिति को कूटबद्ध करता है:

  • यदि प्रक्रिया सामान्य रूप से $?बाहर निकलती है, तो इसकी निकास स्थिति है।
  • यदि प्रक्रिया एक सिग्नल द्वारा मार दी गई थी तो $?अधिकांश सिस्टम पर 128 प्लस सिग्नल संख्या है। POSIX केवल अनिवार्य है जो $?इस मामले में 128 से अधिक है; ksh93 128 के बजाय 256 को जोड़ता है। मैंने कभी एक यूनिक्स संस्करण नहीं देखा है जो सिग्नल संख्या में एक स्थिरांक जोड़ने के अलावा कुछ भी नहीं करता है।

इस प्रकार एक शेल स्क्रिप्ट में आप निर्णायक रूप से यह नहीं बता सकते हैं कि ksh93 को छोड़कर कोई कमांड सिग्नल से मारा गया था या 128 से अधिक की स्थिति कोड के साथ बाहर निकल गया था। कार्यक्रमों में 128 से अधिक स्थिति कोड के साथ बाहर निकलना बहुत दुर्लभ है, क्योंकि प्रोग्रामर $?अस्पष्टता के कारण इससे बचते हैं ।

SIGINT ज्यादातर यूनिक्स वेरिएंट पर सिग्नल 2 है, इस प्रकार $?SIGINT द्वारा मार दी गई प्रक्रिया के लिए 128 + 2 = 130 है। आप SIGHTUP के लिए 129, SIGKILL के लिए 137, आदि देखेंगे।


एक बहुत ही बेहतर शब्द और मेरे लिए बिंदु से अधिक भले ही वह सार रूप में समान बातें कहे। आप स्पष्ट करना चाहते हैं कि $?बॉर्न जैसे गोले के लिए ही है। yashएक अलग (लेकिन अभी भी POSIX) व्यवहार के लिए भी देखें । POSIX + XSI (यूनिक्स) के अनुसार, एक kill -2 "$pid"प्रक्रिया के लिए एक संकेत भेजेगा, लेकिन वास्तविक संकेत संख्या 2 नहीं हो सकती है, इसलिए $? जरूरी नहीं कि 128 + 2 (या 256 + 2 या 384 + 2) kill -l "$?"होगा , हालांकि INT, वापस आ जाएगा , यही कारण है कि मैं पोर्टेबिलिटी के लिए सलाह दूंगा कि वे खुद को संख्याओं का संदर्भ न दें।
स्टीफन चेज़ेलस

8

जो आपके शेल पर निर्भर करता है। से bash(1)आदमी पेज, शेल व्याकरण खंड, सरल कमांड उपधारा:

एक साधारण कमांड का रिटर्न मान [...] 128+ n है यदि कमांड सिग्नल n द्वारा समाप्त किया जाता है ।

चूंकि SIGINTआपका सिस्टम सिग्नल नंबर 2 है, बैश के तहत चलने पर रिटर्न वैल्यू 130 है।


1
दुनिया में आप इसे कैसे देखते हैं, या यह भी जानते हैं कि कहां देखना है? मैं आपकी प्रतिभा के सामने झुकता हूं।
कोरी क्लेन

1
@CoryKlein: अनुभव, ज्यादातर। ओह, और आप संभवतः signal(7)मैन पेज भी चाहते हैं।
इग्नासियो वाज़केज़-अब्राम्स

सुन्दर सामान; क्या आप जानते हैं कि क्या मैंने संयोग से उन स्थिरांक के साथ सी में फाइलें शामिल की हैं? +1
रुई एफ रिबेरो

@CoryKlein आपने इसे सही उत्तर के रूप में क्यों नहीं चुना है?
रुई एफ रिबेरो

3

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

लगभग 2 महीने पहले, मैंने वेटपिड () के बजाय वेटिड () का उपयोग करने के लिए बॉर्न शेल के प्रतीक्षा / नौकरी नियंत्रण भाग को फिर से लिखा। यह 0xFF के साथ निकास कोड को मास्क करने वाली सीमा को हटाने के लिए किया गया था।

वेटिड () इंटरफ़ेस बहुत साफ है कि 1980 से यूएनओएस से कॉल () कॉल को छोड़कर पिछले प्रतीक्षा () कार्यान्वयन।

आपको उस आदमी पृष्ठ को पढ़ने में रुचि हो सकती है:

http://schillix.sourceforge.net/man/man1/bosh.1.html

और पृष्ठ 8 पर वर्तमान में "पैरामीटर सबस्टीट्यूशन" अनुभाग देखें।

नए चर .sh। * को वेटिड () इंटरफ़ेस के लिए पेश किया गया है। इस इंटरफ़ेस का अब $ के लिए ज्ञात संख्याओं के लिए अस्पष्ट अर्थ नहीं है? और इंटरफेसिंग को बहुत आसान बनाते हैं।

ध्यान दें कि आपके पास इस सुविधा का उपयोग करने में सक्षम होने के लिए एक POSIX आज्ञाकारी वेटिड () होने की आवश्यकता है, इसलिए Mac OS X और Linux वर्तमान में इसे प्रदान नहीं करते हैं, लेकिन वेटिड () कॉल पर वेटिड () का अनुकरण किया जाता है, इसलिए गैर- POSIX प्लेटफ़ॉर्म आपको अभी भी एग्ज़िट कोड से केवल 8 बिट ही मिलेगा।

संक्षेप में: .sh.status संख्यात्मक बाहर निकलने का कोड है, .sh.code संख्यात्मक निकास कारण है।

बेहतर पोर्टेबिलिटी के लिए, बाहर निकलने के कारण के शाब्दिक संस्करण के लिए .sh.codename है, उदाहरण के लिए "DUEDED" और .sh.termsig, सिग्नल का एकल नाम जो प्रक्रिया को समाप्त कर देता है।

बेहतर उपयोग के लिए, दो गैर-निकास-संबंधित .sh.codename मान हैं: "NOEXEC" और "NOTFOUND" जो तब उपयोग किए जाते हैं जब कोई प्रोग्राम लॉन्च नहीं किया जा सकता।

मेरी रिपोर्ट के बाद 20 घंटे के भीतर फ्रीबीएसडी ने उनका वेटिड () केर्ल बग को ठीक कर दिया, लिनक्स अभी तक उनके फिक्स से शुरू नहीं हुआ था। मुझे उम्मीद है कि इस सुविधा को पेश करने के 26 साल बाद, जो अभी POSIX में है, सभी OS जल्द ही इसका समर्थन करेंगे।


एक संबंधित उत्तर unix.stackexchange.com/a/453432/5132 है
JDBP
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.