लूप से बाहर निकलने के दौरान बैश क्यों नहीं होता है जब उपकेंद्र को समाप्त करने के लिए पाइपिंग किया जाता है?


11

निकास से नीचे कमांड क्यों नहीं है? बाहर निकलने के बजाय, लूप अनिश्चित काल तक चलता है।

जब मैंने अधिक जटिल सेटअप का उपयोग करके इस व्यवहार की खोज की, तो कमांड का सबसे सरल रूप निम्न के लिए कम हो जाता है।

बाहर नहीं निकलता:

while /usr/bin/true ; do echo "ok" | cat ; done | exit 1

ऊपर कोई टाइपो नहीं हैं। प्रत्येक '|' एक पाइप है। The एग्जिट 1 ’एक और प्रक्रिया के लिए खड़ा है जो भाग गया और बाहर हो गया।

मैं उम्मीद करता हूं कि "निकास 1" के कारण लूप पर एसआईजीपीआईपीई होगा (कोई पाठक के साथ पाइप पर लिखें) और लूप को बाहर करने के लिए। लेकिन, लूप चालू रहता है।

आज्ञा क्यों नहीं रुकती?


zsh सामान्य रूप से बाहर निकलता है।
ब्रिअम

जवाबों:


13

यह कार्यान्वयन में एक विकल्प के कारण है।

सोलारिस पर एक ही स्क्रिप्ट चलाने से ksh93एक अलग व्यवहार उत्पन्न होता है:

$ while /usr/bin/true ; do echo "ok" | cat ; done | exit 1
cat: write error [Broken pipe]

क्या समस्या को ट्रिगर करता है आंतरिक पाइपलाइन, इसके बिना, लूप जो भी खोल / ओएस से बाहर निकलता है:

$ while /usr/bin/true ; do echo "ok" ; done | exit 1
$

cat बैश के तहत एक संकेत संकेत मिल रहा है, लेकिन शेल वैसे भी लूप को परेशान कर रहा है।

Process 5659 suspended
[pid 28801] execve("/bin/cat", ["cat"], [/* 63 vars */]) = 0
[pid 28801] --- SIGPIPE (Broken pipe) @ 0 (0) ---
Process 5659 resumed
Process 28801 detached
Process 28800 detached
--- SIGCHLD (Child exited) @ 0 (0) ---
Process 28802 attached
Process 28803 attached
[pid 28803] execve("/bin/cat", ["cat"], [/* 63 vars */]) = 0
Process 5659 suspended
[pid 28803] --- SIGPIPE (Broken pipe) @ 0 (0) ---
Process 5659 resumed
Process 28803 detached
Process 28802 detached
--- SIGCHLD (Child exited) @ 0 (0) ---
Process 28804 attached
Process 28805 attached (waiting for parent)
Process 28805 resumed (parent 5659 ready)
Process 5659 suspended
[pid 28805] execve("/bin/cat", ["cat"], [/* 63 vars */]) = 0
[pid 28805] --- SIGPIPE (Broken pipe) @ 0 (0) ---
Process 5659 resumed
Process 28805 detached
Process 28804 detached
--- SIGCHLD (Child exited) @ 0 (0) ---

बैश प्रलेखन राज्यों:

मूल्य वापस करने से पहले शेल पाइपलाइन में सभी कमांड का इंतजार करता है

Ksh प्रलेखन राज्यों:

प्रत्येक कमांड, संभवतः अंतिम को छोड़कर, एक अलग प्रक्रिया के रूप में चलाया जाता है; शेल अंतिम कमांड के समाप्त होने का इंतजार करता है

POSIX बताता है:

यदि पाइपलाइन बैकग्राउंड में नहीं है (एसिंक्रोनस लिस्ट देखें), तो शेल अंतिम कमांड के लिए पाइपलाइन में निर्दिष्ट के पूरा होने तक प्रतीक्षा करेगा , और सभी कमांड के पूरा होने का इंतजार भी कर सकता है


मुझे लगता है कि यह वास्तव में आंतरिक पाइपलाइन नहीं है जो इस मुद्दे को ट्रिगर करती है, यह है कि echoबिलिन SIGPIPE की उपेक्षा करता है। आप env echoइसके बजाय echo(वास्तविक echoबाइनरी का उपयोग करने के लिए बाध्य करने के लिए) का उपयोग करके समस्या को पुन: उत्पन्न कर सकते हैं । ( { echo hi; echo $? >&2; } | exit 1और के उत्पादन की तुलना भी करें { env echo hi; echo $? >&2; } | exit 1।)
लुकास Werkmeister

1

इस समस्या ने मुझे वर्षों तक परेशान किया है। सही दिशा में कुहनी मारने के लिए jilliagre का धन्यवाद।

मेरे लिनेक्स बॉक्स पर सवाल को थोड़ा टालते हुए, यह उम्मीद के अनुरूप है:

while true ; do echo "ok"; done | head

लेकिन अगर मैं एक पाइप जोड़ता हूं, तो यह अपेक्षित रूप से नहीं छोड़ता है:

while true ; do echo "ok" | cat; done | head

इसने मुझे वर्षों तक निराश किया। जिलियाग्रे द्वारा लिखे गए उत्तर पर विचार करके, मैं इस अद्भुत सुधार के साथ आया:

while true ; do echo "ok" | cat || exit; done | head

QED ...

खैर, काफी नहीं। यहाँ कुछ और अधिक जटिल है:

i=0
while true; do
    i=`expr $i + 1`
    echo "$i" | grep '0$' || exit
done | head

यह सही काम नहीं करता है। मैंने जोड़ा|| exit इसलिए यह जानता है कि कैसे जल्दी समाप्त करना है, लेकिन पहले से echoमेल नहीं खाता है grepताकि लूप तुरंत समाप्त हो जाए। इस मामले में, आप वास्तव में बाहर निकलने की स्थिति में रुचि नहीं रखते हैं grep। मेरे काम के आसपास एक और जोड़ने के लिए है cat। तो, यहाँ "दसवाँ" नामक एक कंट्रीब्यूटेड स्क्रिप्ट है:

#!/bin/bash
i=0
while true; do
    i=`expr $i + 1`
    echo "$i" | grep '0$' | cat || exit
done

यह ठीक से समाप्त जब चलाने के रूप में tens | head । भगवान का शुक्र है।

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