क्यों एक दौड़ की स्थिति है
एक पाइप के दो किनारों को समानांतर में निष्पादित किया जाता है, एक के बाद एक नहीं। इसे प्रदर्शित करने का एक बहुत ही सरल तरीका है: रन
time sleep 1 | sleep 1
इसमें एक दो नहीं बल्कि दो सेकंड लगते हैं।
खोल दो बच्चे की प्रक्रिया शुरू करता है और दोनों के पूरा होने का इंतजार करता है। ये दो प्रक्रियाएं समानांतर रूप से निष्पादित होती हैं: केवल एक ही कारण है कि उनमें से एक दूसरे के साथ सिंक्रनाइज़ हो जाएगी, जब इसे दूसरे के लिए इंतजार करने की आवश्यकता होती है। सिंक्रोनाइज़ेशन का सबसे सामान्य बिंदु वह है जब दाएं-हाथ की ओर वाले खंड अपने मानक इनपुट पर पढ़ने के लिए डेटा की प्रतीक्षा कर रहे हों, और बाएं हाथ की ओर अधिक डेटा लिखने पर यह अनब्लॉक हो जाता है। आक्षेप तब भी हो सकता है, जब दाएं-हाथ की ओर डेटा पढ़ने के लिए धीमा हो और बाएं हाथ के साइड ब्लॉक अपने लेखन ऑपरेशन में तब तक हों जब तक कि दाएं-हाथ की ओर अधिक डेटा नहीं पढ़ता है (पाइप में एक बफर ही है, द्वारा प्रबंधित कर्नेल, लेकिन इसका एक छोटा अधिकतम आकार है)।
सिंक्रनाइज़ेशन के एक बिंदु को देखने के लिए, निम्न आदेशों का पालन करें ( sh -x
प्रत्येक कमांड को प्रिंट करता है क्योंकि यह इसे निष्पादित करता है):
time sh -x -c '{ sleep 1; echo a; } | { cat; }'
time sh -x -c '{ echo a; sleep 1; } | { cat; }'
time sh -x -c '{ echo a; sleep 1; } | { sleep 1; cat; }'
time sh -x -c '{ sleep 2; echo a; } | { cat; sleep 1; }'
जब तक आप जो निरीक्षण करते हैं उसके साथ सहज होने तक विविधताओं के साथ खेलें।
कंपाउंड कमांड दी
cat tmp | head -1 > tmp
बाएं हाथ की प्रक्रिया निम्न कार्य करती है (मैंने केवल वही चरण सूचीबद्ध किए हैं जो मेरे स्पष्टीकरण के लिए प्रासंगिक हैं):
- बाहरी कार्यक्रम
cat
को तर्क के साथ निष्पादित करें tmp
।
tmp
पढ़ने के लिए खोलें ।
- हालांकि यह फ़ाइल के अंत तक नहीं पहुँचा है, फ़ाइल से एक हिस्सा पढ़ें और इसे मानक आउटपुट में लिखें।
दाहिने हाथ की प्रक्रिया निम्नलिखित करती है:
- मानक आउटपुट को रीडायरेक्ट करने के लिए
tmp
, इस प्रक्रिया में फ़ाइल को छोटा कर देता है।
- बाहरी कार्यक्रम
head
को तर्क के साथ निष्पादित करें -1
।
- मानक इनपुट से एक पंक्ति पढ़ें और इसे मानक आउटपुट पर लिखें।
सिंक्रोनाइज़ेशन का एकमात्र बिंदु यह है कि दाएं -3 बाएं के लिए प्रतीक्षा करता है-3 ने एक पूरी लाइन संसाधित की है। बाएं -2 और दाएं -1 के बीच कोई तालमेल नहीं है, इसलिए वे किसी भी क्रम में हो सकते हैं। वे किस क्रम में होते हैं, यह अनुमान लगाने योग्य नहीं है: यह सीपीयू आर्किटेक्चर पर निर्भर करता है, शेल पर, कर्नेल पर, जिस पर कोर की प्रक्रिया निर्धारित होती है, उस समय सीपीयू के आसपास क्या होता है, आदि को बाधित करता है।
व्यवहार को कैसे बदलें
आप सिस्टम सेटिंग बदलकर व्यवहार नहीं बदल सकते। कंप्यूटर वही करता है जो आप उसे करने के लिए कहते हैं। आपने इसे समानांतर रूप tmp
से छोटा और पढ़ने के लिए कहा था tmp
, इसलिए यह दो चीजों को समानांतर में करता है।
ठीक है, एक "सिस्टम सेटिंग" है जिसे आप बदल सकते हैं: आप /bin/bash
एक अलग प्रोग्राम द्वारा प्रतिस्थापित कर सकते हैं जो बैश नहीं है। मुझे उम्मीद है कि यह बिना कहे चले जाएंगे कि यह अच्छा विचार नहीं है।
यदि आप चाहते हैं कि पाइप के बायीं ओर से पहले छंटनी हो, तो आपको इसे पाइप लाइन के बाहर रखना होगा, उदाहरण के लिए:
{ cat tmp | head -1; } >tmp
या
( exec >tmp; cat tmp | head -1 )
मुझे नहीं पता कि आप ऐसा क्यों चाहते हैं। उस फ़ाइल से पढ़ने का क्या मतलब है जिसे आप खाली होना जानते हैं?
इसके विपरीत, यदि आप चाहते हैं कि आउटपुट रीडायरेक्शन (ट्रंकेशन सहित) cat
समाप्त होने के बाद रीडिंग हो, तो आपको मेमोरी में डेटा को पूरी तरह से बफर करने की आवश्यकता है, जैसे।
line=$(cat tmp | head -1)
printf %s "$line" >tmp
या किसी भिन्न फ़ाइल पर लिखें और फिर उसे स्थान पर ले जाएं। यह आमतौर पर लिपियों में चीजों को करने का सबसे मजबूत तरीका है, और इसका फायदा यह है कि मूल नाम के माध्यम से दिखाई देने से पहले फ़ाइल को पूर्ण रूप से लिखा जाता है।
cat tmp | head -1 >new && mv new tmp
Moreutils संग्रह एक प्रोग्राम है जो सिर्फ इतना है कि कहा जाता है, करता है शामिल हैं sponge
।
cat tmp | head -1 | sponge tmp
कैसे स्वचालित रूप से समस्या का पता लगाने के लिए
यदि आपका लक्ष्य बुरी तरह से लिखी गई लिपियों को लेना था और अपने आप पता लगा लिया कि वे कहाँ टूटते हैं, तो क्षमा करें, जीवन इतना सरल नहीं है। रनटाइम विश्लेषण समस्या को मज़बूती से नहीं खोजेगा क्योंकि कभी-कभी cat
ट्रंकेशन होने से पहले रीडिंग खत्म हो जाती है। सिद्धांत रूप में स्थैतिक विश्लेषण कर सकते हैं; आपके प्रश्न में सरलीकृत उदाहरण शेलचेक द्वारा पकड़ा गया है , लेकिन यह अधिक जटिल स्क्रिप्ट में एक समान समस्या नहीं पकड़ सकता है।