2014-10-20 6 views
20

मान लीजिए मैं निम्नलिखित है स्क्रिप्ट: -बैश: सिर और पूंछ बैश स्क्रिप्ट के साथ व्यवहार

test.sh

#!/bin/bash 
command1 #prints 5 lines 
command2 #prints 3 lines 

मैं test.sh|head -n5

साथ स्क्रिप्ट क्या इस में होगा चलाने मामला? क्या यह दोनों आदेशों को चलाएगा? या यह कमांड 1 के बाद रुक जाएगा? यदि मैं इसे -n1 के साथ कॉल करता हूं तो क्या होगा?

पृष्ठभूमि: मैं एक बहुत ही बुनियादी सवाल पूछ रहा हूं, लेकिन मैंने वास्तव में कुछ दिलचस्प देखा। मेरी स्क्रिप्ट (अलग-अलग) 7,000 फाइलों को संसाधित कर रही थी और प्रत्येक फाइल आउटपुट की 1 लाइन बनाती है। यह 7 मिनट लगते हैं स्क्रिप्ट पूरी तरह से चलते हैं, लेकिन सिर करने के लिए -n1 दिया मुझे तुरंत स्क्रिप्ट तुरंत तरह पहली फ़ाइल केवल

संपादित संसाधित करने के बाद समाप्त कर दिया है: के बाद मेरी स्क्रिप्ट है

for i in $(ls filepath);do 
    echo "$i" # issue here 
    python mySript "$i" > "/home/user/output/""$i"".out" 
    fi 
done 

को हटाकर प्रतिबिंब स्क्रिप्ट को हेड-एन 1 के साथ पूर्ण 7 मिनट चलाने में सक्षम बनाता है, लेकिन गूंज के साथ यह केवल पहली पंक्ति प्रिंट करता है और बाहर निकलता है।

+0

यह पूरी तरह से कमांड चलाएगा और फिर आउटपुट को सीधे सिर पर पास कर देगा। ऐसा लगता है कि सब कुछ ठीक तरह से काम कर रहा है, मुझे समझ में नहीं आता कि आप क्या पूछ रहे हैं? –

+0

यह 'echo' अंतर्निहित कमांड के बाद से बैश का व्यवहार प्रतीत होता है। 'echo' को'/bin/echo' में बदलने का प्रयास करें और देखें कि क्या खुशी है। – ymonad

+0

@ymonad आप सही हैं, क्या आप इस व्यवहार पर और विस्तार कर सकते हैं? – RedX

उत्तर

16

यह एक काफी दिलचस्प मुद्दा है! इसे पोस्ट करने के लिए धन्यवाद!

मैं मान लिया है कि इस पहली कुछ पंक्तियों संसाधित करने के बाद head रास्ते के रूप में होता है, तो SIGPIPE संकेत के लिए भेजा स्क्रिप्ट चलाने जब यह echo $x अगली बार करने की कोशिश करता है। मैंने इस सिद्धांत को साबित करने के लिए रेडएक्स की लिपि का उपयोग किया:

#!/usr/bin/bash 
rm x.log 
for((x=0;x<5;++x)); do 
    echo $x 
    echo $x>>x.log 
done 

जैसा कि आपने वर्णन किया है, यह काम करता है! t.sh|head -n 2 का उपयोग करके यह स्क्रीन पर केवल 2 लाइनें और x.log पर लिखता है। लेकिन SIGPIPE फँसाने इस व्यवहार परिवर्तन ...

#!/usr/bin/bash 
trap "echo SIGPIPE>&2" PIPE 
rm x.log 
for((x=0;x<5;++x)); do 
    echo $x 
    echo $x>>x.log 
done 

आउटपुट:

$ ./t.sh |head -n 2 
0 
1 
./t.sh: line 5: echo: write error: Broken pipe 
SIGPIPE 
./t.sh: line 5: echo: write error: Broken pipe 
SIGPIPE 
./t.sh: line 5: echo: write error: Broken pipe 
SIGPIPE 

लेखन त्रुटि stdout रूप में होता है पहले से ही पाइप के दूसरे छोर के रूप में बंद कर दिया है बंद कर दिया है। और बंद पाइप को लिखने का कोई भी प्रयास एक सिगिप सिग्नल का कारण बनता है, जो डिफ़ॉल्ट रूप से प्रोग्राम को समाप्त करता है (man 7 signal देखें)। X.log में अब 5 लाइनें हैं।

यह भी बताता है कि /bin/echo समस्या का हल क्यों हुआ।

rm x.log 
for((x=0;x<5;++x)); do 
    /bin/echo $x 
    echo "Ret: $?">&2 
    echo $x>>x.log 
done 

आउटपुट::

$ ./t.sh |head -n 2 
0 
Ret: 0 
1 
Ret: 0 
Ret: 141 
Ret: 141 
Ret: 141 

दशमलव 141 = हेक्स 8D निम्न स्क्रिप्ट देखें। हेक्स 80 का मतलब है कि एक सिग्नल प्राप्त हुआ था, हेक्स 0 डी सिगिप के लिए है। तो जब /bin/echo ने stdout को लिखने की कोशिश की तो उसे एक सिगिप मिला और इसे स्क्रिप्ट चलाने के बजाए (डिफ़ॉल्ट व्यवहार के रूप में) समाप्त कर दिया गया।

+0

बहुत बढ़िया स्पष्टीकरण और आसपास के काम भी काफी साफ था। मुझे लगता है कि बैश ऐसी स्थिति को क्यों संभाल नहीं पाता है। यह पाइप बंद करने और सिगिप भेजने के लिए समझ में आता है, अन्यथा खोल में प्रक्रियाएं चलती रहेंगी और प्रोग्रामर को हर प्रक्रिया में बाहर निकलने के परिदृश्यों को संभालना होगा। आपको बहुत बहुत धन्यवाद! –

+0

@MangatRai: दरअसल [टैग: बैश] SIGPIPE को फँसाने से स्थिति को संभाल सकता है। आमतौर पर एक पाइप बंद करते हैं जबकि अन्य प्रक्रिया इसे लिखना चाहती है एक त्रुटि है। तो डिफ़ॉल्ट व्यवहार लेखक को समाप्त करना है। लेकिन अगर प्रोग्रामर जानता है कि यह वास्तविक त्रुटि नहीं है, तो समस्या को हल करने के लिए कार्रवाई कर सकते हैं। और यह स्थिति बाश के लिए नहीं है, लेकिन किसी भी निष्पादन योग्य के लिए जो एक पाइप को लिखती है। यदि 'हेड' का उपयोग किया जाता है तो "पाइप" "विचार" कर सकता है कि पहली कुछ पंक्तियों के बाद पाइप के स्रोत पक्ष को समाप्त करना सामान्य है। – TrueY

+0

यह सच है, वाई? पहले ही समझाया गया है (क्षमा करें) –

1

यह एक टिप्पणी के बाद एक उत्तर है लेकिन यह एक टिप्पणी के लिए बहुत बड़ा है।

मैं स्क्रिप्ट निम्नलिखित की कोशिश की:

#!/usr/bin/env bash 

rm -f "test_head.log" 
echo "1 line" 
echo "1 line" >> "test_head.log" 
echo "2 line" 
echo "2 line" >> "test_head.log" 
echo "3 line" 
echo "3 line" >> "test_head.log" 
echo "4 line" 
echo "4 line" >> "test_head.log" 
echo "5 line" 
echo "5 line" >> "test_head.log" 
echo "6 line" 
echo "6 line" >> "test_head.log" 
echo "7 line" 
echo "7 line" >> "test_head.log" 
echo "8 line" 
echo "8 line" >> "test_head.log" 

तो मैं साथ स्क्रिप्ट चलाने:

./test_head.sh | सिर -n1

बिल्ली उत्पादन होता है (मेरे आश्चर्य करने के लिए):

1 लाइन

मुझे पता नहीं क्या हो रहा है है।

@ymonad टिप्पणी पढ़ने के बाद मैंने /bin/echo के साथ इसे आजमाया और समस्या को हल किया। मुझे आशा है कि वह इस व्यवहार के बारे में और अधिक समझा सकता है।

8

अच्छी खोज। मेरे परीक्षणों के मुताबिक यह ठीक है जैसा आपने कहा था। उदाहरण के लिए मैं इस स्क्रिप्ट है कि बस cpu खाती है, तो हमसे top में यह स्थान जाने के लिए:

for i in `seq 10` 
    do echo $i 
    x=`seq 10000000` 
done 

head -n1 हम देखते आदेश पहली पंक्ति के बाद लौटने के साथ स्क्रिप्ट गरमा। यह head व्यवहार है: यह अपना काम पूरा कर चुका है, इसलिए यह आपको रोक सकता है और आपको नियंत्रण वापस कर सकता है।

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

for i in xrange(10): 
    print i 
    range(10000000) 

जब यह और पाइपिंग चल:

की यह एक अजगर स्क्रिप्ट के साथ की कोशिश करते हैं

$ python -u test.py | head -n1 
0 
Traceback (most recent call last): 
    File "test.py", line 2, in <module> 
    print i 
IOError: [Errno 32] Broken pipe 

-u विकल्प अजगर बताता है स्वचालित रूप से stdin और stdout फ्लश करने के लिए, जैसा कि बाश करेगा। तो आप देखते हैं कि प्रोग्राम वास्तव में एक त्रुटि के साथ बंद हो जाता है।

+1

पायथन का अच्छा उपयोग। – Davidmh

+1

रूट के कारण पायथन का उपयोग करना समस्या बहुत प्यारी थी। –

+1

@ मंगलराई वास्तव में मैंने विपरीत किया, मैंने सोचा: बैश? नहीं, चलिए इसे पायथन में लिखते हैं, और त्रुटि पॉप अप हो जाती है :) लेकिन अगली बार मुझे बैश के साथ एक अजीब समस्या है, मैं फिर से अजगर का उपयोग करूंगा! –

संबंधित मुद्दे