बैश: प्रक्रिया प्रतिस्थापन में त्रुटियों का प्रचार कैसे करें?


19

मैं चाहता हूं कि जब भी उनके साथ निष्पादित कोई कमांड विफल हो जाए तो मैं अपनी शेल स्क्रिप्ट को विफल कर दूं।

आमतौर पर मैं ऐसा करता हूं:

set -e
set -o pipefail

(आमतौर पर मैं set -uभी जोड़ता हूं )

बात यह है कि उपरोक्त कोई भी प्रक्रिया प्रतिस्थापन के साथ काम नहीं करता है। यह कोड "ओके" प्रिंट करता है और रिटर्न कोड = 0 से बाहर निकलता है, जबकि मैं चाहूंगा कि यह विफल हो:

#!/bin/bash -e
set -o pipefail
cat <(false) <(echo ok)

क्या "पाइपफेल" के बराबर कुछ भी है लेकिन प्रक्रिया प्रतिस्थापन के लिए? किसी कमांड को कमांड के आउटपुट को पास करने का कोई अन्य तरीका जैसा कि वे फाइल थे, लेकिन जब भी उन प्रोग्रामों में से कोई भी विफल हो जाता है तो एक त्रुटि बढ़ जाती है?

एक गरीब आदमी के समाधान का पता लगाने अगर उन आदेशों stderr करने के लिए (लेकिन कुछ आदेश sucessful परिदृश्यों में stderr करने के लिए लिखते हैं) का पता लगाने जाएगा।

नामांकित पाइपों का उपयोग करने वाला एक और पॉज़िक्स अनुपालन समाधान होगा, लेकिन मुझे उन आदेशों का उपयोग करने की आवश्यकता है, जो कि उपयोग-प्रक्रिया-प्रतिस्थापन का उपयोग करते हैं क्योंकि संकलित कोड से मक्खी पर बनाया गया ऑनलाइनर, और नामित पाइप बनाने से चीजें जटिल हो जाएंगी (अतिरिक्त कमांड, के लिए त्रुटि फंसाना) उन्हें हटाना, आदि)


नामित पाइप को हटाने के लिए आपको त्रुटियों को फंसाने की आवश्यकता नहीं है। वास्तव में, यह एक अच्छा तरीका नहीं है। विचार करें mkfifo pipe; { rm pipe; cat <file; } >pipe। वह कमांड तब तक लटकेगा जब तक कि एक पाठक नहीं खुल जाता है pipeक्योंकि यह वह शेल है जो करता है open()और इसलिए जैसे ही pipefs लिंक पर एक रीडर होता pipeहै rm'd है और फिर catउस पाइप के लिए शेल के डिस्क्रिप्टर पर infile कॉपी करता है। और वैसे भी, यदि आप एक प्रक्रिया से बाहर एक त्रुटि का प्रचार करना चाहते हैं: <( ! : || kill -2 "$$")
mikeserv

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

इसलिए उपयोग करें kill -2 0
मिकसेर्व जूल 22'15

दुर्भाग्य से "किल -2 0" मार देगा (संकेत) अजगर। मल्टीथ्रेड एप्लिकेशन के भीतर व्यावसायिक तर्क के प्रदर्शन के लिए सिग्नल हैंडलर लिखना कुछ ऐसा नहीं है जिसे मैं आगे देख रहा हूं :-)
जुआनलोन

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

जवाबों:


6

आप केवल उदाहरण के लिए उस मुद्दे के आसपास काम कर सकते हैं:

cat <(false || kill $$) <(echo ok)
other_command

SIGTERMदूसरी कमांड निष्पादित होने ( other_command) से पहले स्क्रिप्ट का सबस्क्रिप्शन डी है । echo okआदेश "कभी-कभी" निष्पादित किया जाता है: समस्या यह है कि प्रक्रिया प्रतिस्थापन अतुल्यकालिक कर रहे हैं। इस बात की कोई गारंटी नहीं है कि kill $$कमांड को कमांड से पहले या बाद में निष्पादित किया echo okगया है। यह ऑपरेटिंग सिस्टम शेड्यूलिंग की बात है।

इस तरह एक बैश स्क्रिप्ट पर विचार करें:

#!/bin/bash
set -e
set -o pipefail
cat <(echo pre) <(false || kill $$) <(echo post)
echo "you will never see this"

उस स्क्रिप्ट का आउटपुट हो सकता है:

$ ./script
Terminated
$ echo $?
143           # it's 128 + 15 (signal number of SIGTERM)

या:

$ ./script
Terminated
$ pre
post

$ echo $?
143

आप इसे आज़मा सकते हैं और कुछ कोशिशों के बाद, आप आउटपुट में दो अलग-अलग ऑर्डर देखेंगे। पहले एक में स्क्रिप्ट को समाप्त किया गया था इससे पहले कि अन्य दो echoकमांड फाइल डिस्क्रिप्टर पर लिख सकें। दूसरे में falseया killकमांड के बाद संभवतः कमांड को शेड्यूल किया गया था echo

या अधिक सटीक होने के लिए: शिलालेख प्रक्रिया को सिग्नल भेजने वाली यूटिलिटी signal()का सिस्टम कॉल इको सिस्कॉल की तुलना में बाद में या पहले निर्धारित किया गया था (या वितरित किया गया था) ।killSIGTERMwrite()

लेकिन फिर भी, स्क्रिप्ट बंद हो जाती है और बाहर निकलने का कोड 0. नहीं है। इसलिए यह आपके मुद्दे को हल करना चाहिए।

एक और उपाय , निश्चित रूप से, इसके लिए नामित पाइप का उपयोग करना है। लेकिन, यह आपकी स्क्रिप्ट पर निर्भर करता है कि नामित पाइप या ऊपर दिए गए वर्कअराउंड को लागू करना कितना जटिल होगा।

संदर्भ:


2

रिकॉर्ड के लिए, और भले ही उत्तर और टिप्पणियां अच्छी और सहायक थीं, मैंने कुछ अलग लागू किया (मुझे मूल प्रक्रिया में संकेत प्राप्त करने के बारे में कुछ प्रतिबंध थे जो मैंने प्रश्न में उल्लेख नहीं किया था)

मूल रूप से, मैंने कुछ इस तरह से काम किया:

command <(subcomand 2>error_file && rm error_file) <(....) ...

फिर मैं त्रुटि फ़ाइल की जांच करता हूं। यदि यह मौजूद है, तो मुझे पता है कि क्या सबकॉमैंड विफल हो गया (और error_file की सामग्री उपयोगी हो सकती है)। अधिक क्रिया और हैकिश जिसे मैं मूल रूप से चाहता था, लेकिन एक-लाइनर बैश कॉमरैंड में नामित पाइप बनाने की तुलना में कम बोझिल।


आपके लिए जो भी काम करता है वह आमतौर पर सबसे अच्छा तरीका है। विशेष रूप से वापस आने और जवाब देने के लिए धन्यवाद - सेल्फी मेरे पसंदीदा हैं।
मिकसर्व

2

यह उदाहरण दिखाता है कि कैसे killएक साथ उपयोग करना है trap

#! /bin/bash
failure ()
{
  echo 'sub process failed' >&2
  exit 1
}
trap failure SIGUSR1
cat < <( false || kill -SIGUSR1 $$ )

लेकिन killअपनी उप प्रक्रिया से मूल प्रक्रिया में एक वापसी कोड पारित नहीं कर सकते।


मैं पर स्वीकार किए जाते हैं जवाब इस बदलाव की तरह
sehe

1

इसी तरह से जब आप एक POSIX शेल के साथ लागू$PIPESTATUS$pipestatus करेंगे / करेंगे जो इसका समर्थन नहीं करता है , तो आप उन्हें एक पाइप के माध्यम से पास करके कमांडों के निकास की स्थिति प्राप्त कर सकते हैं:

unset -v false_status echo_status
{ code=$(
    exec 3>&1 >&4 4>&-
    cat 3>&- <(false 3>&-; echo >&3 "false_status=$?") \
             <(echo ok 3>&-; echo >&3 "echo_status=$?")
);} 4>&1
cat_status=$?
eval "$code"
printf '%s_code=%d\n' cat   "$cat_status" \
                      false "$false_status" \
                      echo  "$echo_status"

जो देता है:

ok
cat_code=0
false_code=1
echo_code=0

या आप उपयोग कर सकते हैं pipefailऔर प्रक्रिया प्रतिस्थापन को हाथ से लागू कर सकते हैं जैसे आप गोले के साथ करेंगे जो इसका समर्थन नहीं करते हैं:

set -o pipefail
{
  false <&5 5<&- | {
    echo OK <&5 5<&- | {
      cat /dev/fd/3 /dev/fd/4
    } 4<&0 <&5 5<&-
  } 3<&0
} 5<&0
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.