पाइप एक इन-कर्नेल फ़ाइल-सिस्टम में खोली गई फ़ाइल है और एक नियमित फ़ाइल ऑन-डिस्क के रूप में सुलभ नहीं है। यह स्वचालित रूप से केवल एक निश्चित आकार में बफर्ड होता है और अंततः पूर्ण होने पर ब्लॉक हो जाता है। ब्लॉक-डिवाइसेस पर खटास वाली फाइलों के विपरीत, पाइप चरित्र उपकरणों की तरह बहुत व्यवहार करते हैं, और इसलिए आमतौर पर समर्थन नहीं करते हैंlseek()
और उनसे पढ़े गए डेटा को फिर से नहीं पढ़ा जा सकता है जैसा कि आप एक नियमित फ़ाइल के साथ कर सकते हैं।
यहां एक स्ट्रिंग एक नियमित फाइल है जो माउंटेड फाइल-सिस्टम में बनाई गई है। शेल फ़ाइल बनाता है और इसके एकमात्र फ़ाइल सिस्टम लिंक (और इसलिए इसे हटाने) को हटाने से पहले इसके डिस्क्रिप्टर को बनाए रखता है, इससे पहले कि वह फ़ाइल से / से एक बाइट लिखता / पढ़ता है। कर्नेल फ़ाइल के लिए आवश्यक स्थान बनाए रखेगा जब तक कि सभी प्रक्रियाएं इसके लिए सभी विवरणकों को जारी नहीं करती हैं। यदि इस तरह के डिस्क्रिप्टर से पढ़ने वाला बच्चा ऐसा करने की क्षमता रखता है, तो इसे lseek()
दोबारा पढ़ा जा सकता है ।
दोनों मामलों में टोकन <<<
और |
फ़ाइल-डिस्क्रिप्टर का प्रतिनिधित्व करते हैं और जरूरी नहीं कि फाइलें खुद ही हों। आप इस बात का बेहतर अंदाजा लगा सकते हैं कि क्या कुछ इस तरह से किया जा रहा है:
readlink /dev/fd/1 | cat
... या ...
ls -l <<<'' /dev/fd/*
दो फाइलों के बीच सबसे महत्वपूर्ण अंतर यह है कि यहां स्ट्रिंग / डॉक बहुत ज्यादा एक बार में होने वाला मामला है - शेल बच्चे को रीड डिस्क्रिप्टर की पेशकश करने से पहले इसमें सभी डेटा लिखता है। दूसरी ओर, शेल उपयुक्त डिस्क्रिप्टर पर पाइप को खोलता है और बच्चों को पाइप के प्रबंधन के लिए कांटे देता है - और इसलिए इसे दोनों सिरों पर समवर्ती रूप से लिखा / पढ़ा जाता है।
ये भेद, हालांकि, केवल आम तौर पर सच हैं। जहां तक मुझे पता है (जो वास्तव में अब तक नहीं है) यह बहुत ज्यादा हर शेल के बारे में सच है जो <<<
यहाँ <<
के एकल-अपवाद के साथ दस्तावेज़-पुनर्निर्देशन के लिए यहाँ स्ट्रिंग-शॉर्ट को संभालता है yash
। yash
, busybox
, dash
, और अन्य ash
वेरिएंट पाइप के साथ वापस करने के लिए यहां-दस्तावेज है, हालांकि, और उन के गोले में वहाँ वास्तव में सभी के बाद दोनों के बीच बहुत कम अंतर है करते हैं।
ठीक है - दो अपवाद। अब जब मैं इसके बारे में सोच रहा हूं, ksh93
वास्तव में सभी के लिए एक पाइप नहीं करता है |
, बल्कि पूरे व्यापार w / sockets को संभालता है - हालांकि यह एक डिलीट tmp फाइल करता है <<<*
जैसा कि अन्य लोग करते हैं। क्या अधिक है, यह केवल पाइपलाइन के अलग-अलग खंडों को एक उप-परिवेश में रखता है जो एक प्रकार का पॉज़ीक व्यंजना है जो कम से कम यह एक उप- प्रकार की तरह कार्य करता है , और इसलिए कांटे भी नहीं करता है।
तथ्य यह है कि @ PSkocik का बेंचमार्क (जो बहुत उपयोगी है) यहाँ परिणाम कई कारणों से व्यापक रूप से भिन्न हो सकते हैं , और इनमें से अधिकांश कार्यान्वयन पर निर्भर हैं। यहाँ-दस्तावेज़ सेटअप के लिए सबसे बड़ा कारक लक्ष्य ${TMPDIR}
फ़ाइल-सिस्टम प्रकार और वर्तमान कैश कॉन्फ़िगरेशन / उपलब्धता होगा, और फिर भी लिखे जाने वाले डेटा की मात्रा moreso होगी। पाइप के लिए यह स्वयं शेल प्रक्रिया का आकार होगा, क्योंकि आवश्यक कांटे के लिए प्रतियां बनाई जाती हैं। इस तरह से पाइपलाइन सेटअप bash
में भयानक है ( $(
कमांड )
प्रतिस्थापन शामिल करने के लिए ) - क्योंकि यह बड़ा और बहुत धीमा है, लेकिन इसके साथ ksh93
शायद ही कोई फर्क पड़ता है।
यहाँ एक और छोटा खोल स्निपेट दिखाया गया है कि कैसे एक पाइप लाइन के लिए एक उप खोल को विभाजित करता है:
pipe_who(){ echo "$$"; sh -c 'echo "$PPID"'; }
pipe_who
pipe_who | { pipe_who | cat /dev/fd/3 -; } 3<&0
32059 #bash's pid
32059 #sh's ppid
32059 #1st subshell's $$
32111 #1st subshell sh's ppid
32059 #2cd subshell's $$
32114 #2cd subshell sh's ppid
एक पाइपलाइन्ड pipe_who()
कॉल रिपोर्ट और वर्तमान शेल में एक रन की रिपोर्ट के बीच का अंतर एक (
उपधारा के )
निर्दिष्ट व्यवहार के कारण $$
होता है जब यह विस्तारित होने पर मूल शेल के पीड का दावा करता है। हालांकि सब- bash
डिले निश्चित रूप से अलग-अलग प्रक्रियाएं हैं, $$
विशेष शेल पैरामीटर इस जानकारी का विश्वसनीय स्रोत नहीं है। फिर भी, उपधारा के बच्चे के sh
खोल इसकी रिपोर्ट करने के लिए सही नहीं है $PPID
।