आपको पहले से ही कुछ बहुत अच्छे जवाब मिले। मुझे इस बात पर जोर देना चाहिए कि यहां दो अलग-अलग अवधारणाएं शामिल हैं, जिनमें से समझ काफी मदद करती है:
बैकग्राउंड: फाइल डिस्क्रिप्टर बनाम फाइल टेबल
आपकी फ़ाइल डिस्क्रिप्टर सिर्फ एक संख्या 0 ... n है, जो आपकी प्रक्रिया में फ़ाइल डिस्क्रिप्टर तालिका में अनुक्रमणिका है। कन्वेंशन द्वारा, STDIN = 0, STDOUT = 1, STDERR = 2 (ध्यान दें कि यहां के शब्द STDINआदि) सिर्फ प्रतीक / मैक्रोज़ हैं जो कुछ प्रोग्रामिंग भाषाओं और मैन पेजों में कन्वेंशन द्वारा उपयोग किए जाते हैं, एसटीडीआईएन के लिए एक वास्तविक "ऑब्जेक्ट" नहीं है; इस चर्चा का उद्देश्य, STDIN है 0, आदि)।
वह फ़ाइल डिस्क्रिप्टर तालिका अपने आप में कोई भी जानकारी नहीं रखती है कि वास्तविक फाइल क्या है। इसके बजाय, इसमें एक अलग फ़ाइल तालिका के लिए एक सूचक शामिल है; उत्तरार्द्ध में एक वास्तविक भौतिक फ़ाइल (या ब्लॉक डिवाइस, या पाइप, या जो कुछ भी लिनक्स फाइल तंत्र के माध्यम से संबोधित कर सकता है) और अधिक जानकारी (यानी, चाहे वह पढ़ने या लिखने के लिए हो) के बारे में जानकारी है।
इसलिए जब आप उपयोग करते हैं >या <अपने शेल में होते हैं, तो आप किसी अन्य चीज़ को इंगित करने के लिए संबंधित फ़ाइल डिस्क्रिप्टर के पॉइंटर को बदल देते हैं। सिंटैक्स 2>&1बस वर्णनकर्ता 2 को इंगित करता है जहाँ भी 1 अंक। > file.txtबस file.txtलिखने के लिए खुलता है और STDOUT (फ़ाइल डिक्रिप्टर 1) को उस ओर इंगित करने देता है।
अन्य अच्छाइयाँ हैं, उदाहरण के लिए 2>(xxx) (जैसे: एक नई प्रक्रिया चल रही है xxx, एक पाइप बनाएँ, पाइप के रीडिंग एंड के फाइल डिस्क्रिप्टर 0 को कनेक्ट करें और मूल प्रक्रिया के फाइल डिस्क्रिप्टर 2 को राइटिंग एंड के राइटिंग सिरे से कनेक्ट करें। पाइप)।
यह आपके शेल के अलावा अन्य सॉफ़्टवेयर में "फ़ाइल हैंडल मैजिक" का आधार भी है। उदाहरण के लिए, आप अपनी पर्ल स्क्रिप्ट में, dupSTDOUT फ़ाइल डिस्क्रिप्टर को दूसरे (अस्थायी) में से एक में लाइसेंस कर सकते हैं, फिर STDOUT को एक नई बनाई गई अस्थायी फ़ाइल में फिर से खोलें। इस बिंदु से, आपकी अपनी पर्ल स्क्रिप्ट से सभी STDOUT आउटपुट औरsystem() उस स्क्रिप्ट की सभी कॉल उस अस्थायी फ़ाइल में समाप्त हो जाएंगी। जब किया जाता है, तो आप dupउस अस्थायी विवरणक को फिर से भेज सकते हैं जिसे आपने इसे सहेजा था, और इसे पूर्व में, जैसा कि सभी पहले से बता चुके हैं। आप उस अस्थायी डिस्क्रिप्टर को इस बीच भी लिख सकते हैं, इसलिए जब आपका वास्तविक STDOUT आउटपुट अस्थायी फ़ाइल में जाता है, तब भी आप वास्तव में वास्तविक STDOUT (आमतौर पर, उपयोगकर्ता) को सामान आउटपुट कर सकते हैं ।
उत्तर
अपने प्रश्न के ऊपर दी गई पृष्ठभूमि की जानकारी को लागू करने के लिए:
किस क्रम में शेल कमांड निष्पादित करता है और पुनर्निर्देशन को स्ट्रीम करता है?
बाएं से दाएं।
<command> > file.txt 2>&1
fork एक नई प्रक्रिया बंद।
file.txtफ़ाइल डिस्क्रिप्टर 1 (STDOUT) में इसके पॉइंटर को खोलें और स्टोर करें।
- बिंदु STDERR (फ़ाइल डिस्क्रिप्टर 2) जो भी हो fd 1 को अभी अंक (जो फिर से पहले से ही खोला गया
file.txtहै)।
exec <command>
यह स्पष्ट रूप से पहले stdout करने के लिए stderr को पुनर्निर्देशित करता है, और फिर परिणामी stdout को file.txt पर पुनर्निर्देशित किया जाता है।
यह समझ में आता है अगर वहाँ केवल एक मेज थे , लेकिन जैसा कि ऊपर बताया गया है कि दो हैं। फ़ाइल डिस्क्रिप्टर एक-दूसरे को पुनरावृत्ति की ओर इशारा नहीं कर रहे हैं, यह सोचने के लिए कोई मतलब नहीं है "STDERR को STREOUT"। सही विचार "बिंदु STDERR है जहाँ भी बिंदुओं के लिए"। यदि आप STDOUT को बाद में बदलते हैं, तो STDERR जहां रहता है, वह जादुई रूप से STDOUT में और परिवर्तन के साथ नहीं जाता है।