क्या> और - से अधिक कुशल> / देव / अशक्त है?


58

कल मैंने एसओ की यह टिप्पणी पढ़ी जो कहती है कि शेल (कम से कम bash) >&-"के समान परिणाम है" >/dev/null

यह टिप्पणी वास्तव में अपनी जानकारी के स्रोत के रूप में ABS गाइड को संदर्भित करती है। लेकिन उस स्रोत का कहना है कि >&-वाक्यविन्यास "फ़ाइल डिस्क्रिप्टर को बंद करता है"।

यह मेरे लिए स्पष्ट नहीं है कि क्या फाइल डिस्क्रिप्टर को बंद करने और इसे शून्य डिवाइस पर पुनर्निर्देशित करने की दो क्रियाएं पूरी तरह से बराबर हैं। तो मेरा सवाल है: क्या वे हैं?

इसकी सतह पर ऐसा लगता है कि एक डिस्क्रिप्टर को बंद करना एक दरवाजे को बंद करने जैसा है, लेकिन इसे एक अशक्त डिवाइस पर पुनर्निर्देशित करना लिम्बो के लिए एक दरवाजा खोल रहा है! दोनों मुझे बिल्कुल एक जैसे नहीं लगते क्योंकि अगर मुझे एक बंद दरवाजा दिखाई देता है, तो मैं इसमें से कुछ भी बाहर फेंकने की कोशिश नहीं करूंगा, लेकिन अगर मैं एक खुला दरवाजा देखता हूं तो मैं मान लूंगा।

दूसरे शब्दों में, मुझे हमेशा आश्चर्य होता >/dev/nullहै कि cat mybigfile >/dev/nullक्या इसका मतलब है कि वास्तव में फ़ाइल के हर बाइट को संसाधित करेगा और इसे लिख देगा /dev/nullजो इसे भूल जाता है। दूसरी ओर, यदि शेल एक बंद फाइल डिस्क्रिप्टर से सामना करता है तो मैं सोचता हूं (लेकिन मुझे यकीन नहीं है) कि यह बस कुछ भी नहीं लिखेगा, हालांकि सवाल यह है कि क्या catअभी भी हर बाइट को पढ़ा जाएगा ।

यह टिप्पणी कहती है >&-और >/dev/null" होना चाहिए " समान है, लेकिन यह मेरे लिए इतना शानदार जवाब नहीं है। मैं मानक या स्रोत कोर या नहीं के कुछ संदर्भ के साथ अधिक आधिकारिक जवाब देना चाहूंगा ...


अगर मैं धर्मार्थ होना चाहता था, तो मैं कहूंगा कि टिप्पणी का मतलब यह नहीं था कि उन्हें उसी तरह से लागू किया गया था, बस यह कि उन दोनों को कार्यक्रम के आउटपुट को देखने से रोकने का एक ही अंतिम परिणाम है।
बरमार

जवाबों:


71

नहीं, आप निश्चित रूप से फ़ाइल डिस्क्रिप्टर 0, 1 और 2 को बंद नहीं करना चाहते हैं।

यदि आप ऐसा करते हैं, तो पहली बार एप्लिकेशन एक फ़ाइल खोलता है, यह स्टडिन / स्टडआउट / स्टडरर बन जाएगा ...

उदाहरण के लिए, यदि आप करते हैं:

echo text | tee file >&-

जब tee(कम से कम कुछ कार्यान्वयन, जैसे कि बिजीबॉक्स ') लिखने के लिए फ़ाइल खोलता है, तो यह फ़ाइल डिस्क्रिप्टर 1 (स्टडआउट) पर खुला होगा। तो दो बार में teeलिखूंगा :textfile

$ echo text | strace tee file >&-
[...]
open("file", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 1
read(0, "text\n", 8193)                 = 5
write(1, "text\n", 5)                   = 5
write(1, "text\n", 5)                   = 5
read(0, "", 8193)                       = 0
exit_group(0)                           = ?

यह सुरक्षा भेद्यता के कारण जाना जाता है। उदाहरण के लिए:

chsh 2>&-

और chsh(एक सेतु अनुप्रयोग) में त्रुटि संदेश लिखने का अंत हो सकता है /etc/passwd

कुछ उपकरण और यहां तक ​​कि कुछ पुस्तकालय भी उस पर पहरा देने की कोशिश करते हैं। उदाहरण के लिए, GNU teeफ़ाइल डिस्क्रिप्टर को 2 से ऊपर ले जाएगा यदि लेखन के लिए खुलने वाली फ़ाइलों को 0, 1, 2 असाइन किया गया है, जबकि डिफ़ॉल्ट रूप teeसे काम नहीं करेगा।

अधिकांश उपकरण, यदि वे stdout को नहीं लिख सकते (क्योंकि उदाहरण के लिए यह खुला नहीं है), stderr पर एक त्रुटि संदेश (उपयोगकर्ता की भाषा में जो स्थानीयकरण फ़ाइलों को खोलने और पार्स करने के लिए अतिरिक्त प्रसंस्करण का मतलब है ...) की सूचना देगा। यह काफी कम कुशल होगा, और संभवतः कार्यक्रम को विफल करने का कारण होगा।

किसी भी मामले में, यह अधिक कुशल नहीं होगा। कार्यक्रम अभी भी एक write()सिस्टम कॉल करेगा। यह केवल तभी अधिक कुशल हो सकता है यदि प्रोग्राम पहले असफल write()सिस्टम कॉल के बाद stdout / stderr को लिखना छोड़ देता है , लेकिन प्रोग्राम आमतौर पर ऐसा नहीं करते हैं। वे आम तौर पर या तो एक त्रुटि के साथ बाहर निकलते हैं या कोशिश करते रहते हैं।


4
मुझे लगता है कि यह उत्तर बेहतर होगा यदि अंतिम पैराग्राफ शीर्ष पर था (क्योंकि यह वही है जो सीधे ओपी के प्रश्न का उत्तर देता है), और यह तब चर्चा में आया कि क्यों यह एक बुरा विचार है भले ही यह ज्यादातर काम करता हो। लेकिन मैं इसे ले लूँगा, एक उत्थान है। ;)
एक CVn

@ स्टीफनचैलेजेलस: जैसा कि माइकल ने कहा, मैंने शीर्ष पर अंतिम पैरा की उम्मीद की होगी, लेकिन यह स्पष्ट करने के लिए धन्यवाद कि वास्तव में केवल समस्याएं पैदा होती हैं। इसलिए मुझे लगता है कि एक सहायक प्रश्न होगा, जब एफडी को बंद करना वास्तव में उपयोगी होगा? या मुझे एक अलग प्रश्न के रूप में पूछना चाहिए?
जमदग्नि

@jamadagni, unix.stackexchange.com/search?q=user%3A22565+%223%3E%26-%22 कुछ उदाहरणों के लिए देखें
स्टीफन चेज़लस

1
@jamadagni यदि स्टीफन द्वारा प्रदान किया गया लिंक प्रश्न का उत्तर नहीं देता है, तो मैं कहूंगा कि यह एक अलग प्रश्न की शुरुआत की तरह लगता है क्योंकि यह सीधे तौर पर दो तरीकों की सापेक्ष दक्षता से संबंधित नहीं है।
बजे एक CVn

1
मैं सराहना करता हूं कि स्टीफन इस महत्वपूर्ण सुरक्षा चेतावनी के साथ शुरू होता है, क्योंकि यह कम दिखाई देगा यदि अंतिम पैराग्राफ शीर्ष पर था। मुझ से +1।
ओलिवियर दुलक

14

IOW मुझे हमेशा आश्चर्य होता >/dev/nullहै कि cat mybigfile >/dev/nullक्या इसका मतलब है कि वास्तव में फ़ाइल के हर बाइट को संसाधित करेगा और इसे लिख देगा /dev/nullजो इसे भूल जाता है।

यह आपके प्रश्न का पूर्ण उत्तर नहीं है, लेकिन हाँ, यह कैसे काम करता है।

catनामित फ़ाइल (एस), या मानक इनपुट को पढ़ता है यदि कोई फ़ाइल नाम नहीं है, और इसके मानक आउटपुट को आउटपुट करता है, जब तक कि यह अंतिम फ़ाइल नाम पर एक ईओएफ (मानक इनपुट सहित) का सामना नहीं करता है। यही इसका काम है।

जोड़कर >/dev/nullआप मानक आउटपुट को / dev / null में रीडायरेक्ट कर रहे हैं। यह एक विशेष फ़ाइल (एक डिवाइस नोड) है जो इसमें लिखी गई किसी भी चीज़ को फेंक देता है (और तुरंत पढ़ने पर ईओएफ लौटाता है)। ध्यान दें कि I / O पुनर्निर्देशन प्रत्येक व्यक्तिगत अनुप्रयोग द्वारा नहीं, शेल द्वारा प्रदान की जाने वाली एक विशेषता है, और यह कि नाम / dev / null के बारे में कुछ भी जादुई नहीं है , केवल वही होता है जो अधिकांश यूनिक्स जैसी प्रणालियों में मौजूद होता है ।

यह नोट करना भी महत्वपूर्ण है कि डिवाइस नोड्स के विशिष्ट मैकेनिक्स ऑपरेटिंग सिस्टम से ऑपरेटिंग सिस्टम में भिन्न होते हैं, लेकिन बिल्ली (जो, एक जीएनयू सिस्टम में, कोर्यूटिल्स का मतलब है) क्रॉस-प्लेटफॉर्म है (समान स्रोत कोड को कम से कम लिनक्स पर चलाने की आवश्यकता है और हर्ड) और इसलिए विशिष्ट ऑपरेटिंग सिस्टम गुठली के लिए निर्भरता नहीं ले सकता है। इसके अतिरिक्त, यह तब भी काम करता है जब आप / dev / null alias बनाते हैं (Linux पर, इसका मतलब है कि एक अन्य नाम के साथ एक ही प्रमुख / मामूली डिवाइस नंबर के साथ एक डिवाइस नोड)। और हमेशा कहीं और लिखने का मामला है जो प्रभावी रूप से एक ही व्यवहार करता है (जैसे, / देव / शून्य)।

यह इस प्रकार है कि cat/ देव / अशक्त के विशेष गुणों से अनजान है, और वास्तव में संभवतः पहली जगह में पुनर्निर्देशन से अनजान है, लेकिन इसे अभी भी बिल्कुल उसी कार्य को करने की आवश्यकता है: यह नामित फ़ाइलों को पढ़ता है, और सामग्री की सामग्री को आउटपुट करता है। / वे फ़ाइल इसके मानक आउटपुट में हैं। यह catहोता है कि शून्य में जाने के लिए मानक आउटपुट कुछ ऐसा नहीं है catजिसका संबंध स्वयं से हो।


2
अपने उत्तर का विस्तार करने के लिए: हाँ, स्मृति के हर बाइट को पढ़ने का cat mybigfile > /dev/nullकारण होगा । और, हर बाइट्स के लिए, यह कॉल करेगा । कार्यक्रम के लिए जाना जाता है, बिल्कुल कुछ भी नहीं करेगा (शायद कुछ तुच्छ बहीखाता को छोड़कर)। हर बाइट को संसाधित करने के लिए लेखन की आवश्यकता नहीं होती है। catbigfilenwrite(1, buffer, n)catwrite/dev/null
जी-मैन

2
मुझे याद है कि जब मैं / देव / नल डिवाइस के लिनक्स कर्नेल स्रोत को पढ़ता था तो मुझे उड़ा दिया जाता था। मैं उम्मीद कर रहा था कि कुछ मुफ्त () आईएनजी बफ़र्स इत्यादि की विस्तृत प्रणाली होगी, लेकिन, नहीं, यह मूल रूप से एक वापसी () है।
ब्रायन मिंटन

4
@ जी-मैन: मुझे नहीं पता कि आप गारंटी दे सकते हैं कि सभी मामलों में सही होना चाहिए। मुझे अब साक्ष्य नहीं मिल सकते हैं, लेकिन मुझे याद है कि catया तो कुछ कार्यान्वयन लागू cpहोगा या mmapस्रोत फ़ाइल के बड़े हिस्से को मेमोरी में काम करेगा , फिर write()मैप किए गए क्षेत्र पर कॉल करेगा। यदि आप लिख रहे थे /dev/null, तो write()कॉल एक ही बार में स्रोत फ़ाइल के पन्नों में खराबी के बिना वापस आ जाएगी, इसलिए यह वास्तव में डिस्क से पढ़ा नहीं जाएगा।
नैट एल्ड्रेडगे

2
इसके अलावा, GNU जैसी catकोई चीज़ कई प्लेटफार्मों पर चलती है, लेकिन स्रोत कोड पर एक आकस्मिक नज़र बहुत सारे दिखाएगी #ifdef: यह शाब्दिक रूप से एक ही कोड नहीं है जो सभी प्लेटफार्मों पर चलता है, और बहुत सारे सिस्टम-निर्भर अनुभाग हैं।
नैट एल्ड्रेडगे

@ नैटएल्ड्रेड: दिलचस्प बिंदु, लेकिन मैं माइकल के जवाब पर बस निर्माण कर रहा था, इसलिए आप मुझे इतना विरोध नहीं कर रहे हैं जितना आप माइकल का विरोध कर रहे हैं।
जी-मैन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.