किसी फ़ाइल का आउटपुट रिडायरेक्ट करने से खुद को खाली फ़ाइल क्यों बनाया जाता है?


19

किसी फ़ाइल का आउटपुट रिडायरेक्ट करने से खुद को खाली फ़ाइल क्यों बनाया जाता है?

बैश में कहा, क्यों करते हैं

less foo.txt > foo.txt

तथा

fold foo.txt > foo.txt

एक खाली उत्पादन foo.txt? चूंकि एक परिशिष्ट जैसे less eggs.py >> eggs.pyपाठ की दो प्रतियों का उत्पादन करता है eggs.py, इसलिए कोई यह उम्मीद कर सकता है कि एक अधिलेखित पाठ की एक प्रति का उत्पादन करेगा।

ध्यान दें, मैं यह नहीं कह रहा हूं कि यह एक बग है, यह यूनिक्स के बारे में कुछ गहरा करने के लिए एक सूचक है।


जवाबों:


20

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

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

क्या आप ऐसी फ़ाइल का उपयोग करना चाहते हैं जो इनपुट और आउटपुट दोनों के साथ कमांड के साथ है जो स्थान संशोधन में समर्थन नहीं करता है, आप एक जोड़ी वर्कअराउंड का उपयोग कर सकते हैं:

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

    fold foo.txt > fold.txt.$$ && mv fold.txt.$$ foo.txt
  • संभावित आंशिक या पूर्ण डेटा हानि की कीमत पर मध्यस्थ फ़ाइल से बचें एक त्रुटि या रुकावट होना चाहिए। इस उदाहरण में, फ़ाइल हटाए जाने से पहले सामग्री को उपधारा (कोष्ठक के अंदर) foo.txtमें इनपुट के रूप में पारित किया जाता है। पिछले इनोड जिंदा रहता है क्योंकि सबस्क्रिप्शन डेटा को पढ़ते समय इसे खुला रखता है। एक ही नाम होने पर आंतरिक उपयोगिता (यहां ) द्वारा लिखी गई फ़ाइल (foldfoo.txt) एक अलग आईनोड को इंगित करता है क्योंकि पुरानी निर्देशिका प्रविष्टि को तकनीकी रूप से हटा दिया गया है, प्रक्रिया के दौरान एक ही नाम के साथ दो अलग-अलग "फाइलें" हैं। जब सबस्क्रिप्शन समाप्त हो जाता है, तो पुराना इनोड जारी होता है और उसका डेटा खो जाता है। यह सुनिश्चित करने के लिए सावधान रहें कि आपके पास एक ही समय में पुरानी फ़ाइल और नए दोनों को अस्थायी रूप से संग्रहीत करने के लिए पर्याप्त स्थान है अन्यथा आप डेटा खो देंगे।

    (rm foo.txt; fold > foo.txt) < foo.txt

3
spongeMoreutils से भी मदद मिल सकती है। fold foo.txt | sponge foo.txt- या fold foo.txt | sponge !$करना भी चाहिए।
slhck

@slhck वास्तव में, स्पंज काम भी कर सकता था। हालाँकि, न तो POSIX द्वारा निर्दिष्ट किया जा रहा है और न ही यूनिक्स की तरह यूनिक्स में मुख्यधारा, यह मौजूद होने की संभावना नहीं है।
जलीगेरे

ऐसा लगता है कि यह नहीं किया जा सकता है बनाया ), हालांकि वर्तमान
slhck


0

बैश में, स्ट्रीम पुनर्निर्देशन ऑपरेटर बाएं ऑपरेंड का मूल्यांकन करने से पहले... > foo.txt खाली हो जाता है ।foo.txt

कोई कमांड प्रतिस्थापन का उपयोग कर सकता है और इसके परिणाम को वर्कअराउंड के रूप में प्रिंट कर सकता है। यह समाधान अन्य उत्तरों की तुलना में कम अतिरिक्त वर्ण लेता है:

printf "%s\n" "$(less foo.txt)" > foo.txt

खबरदार: यह कमांड किसी भी ट्रेलिंग न्यूलाइन (एस) को संरक्षित नहीं करता है foo.txt। अधिक जानकारी के लिए नीचे टिप्पणी अनुभाग में एक नज़र डालें

यहां, स्ट्रीम पुनर्निर्देशन ऑपरेटर से पहले उपधारा $(...)का मूल्यांकन किया जाता है , इसलिए जानकारी का संरक्षण।>


@KamilMaciorowski: वास्तव में, वहाँ है tmp=$(cmd; printf q);  printf '%s' "${tmp%q}"। लेकिन आप इस जवाब के साथ एक और मुद्दा चूक गए: यह "सबमिशन" कहता है जब इसका मतलब है "कमांड प्रतिस्थापन"। हां, कमांड प्रतिस्थापन आमतौर पर उप-प्रकार होते हैं, लेकिन इसके विपरीत नहीं, और उप-भाग, सामान्य रूप से, इस समस्या के लिए कोई सहायता नहीं है।
स्कॉट

@KamilMaciorowski मुझे यह सब याद करने में बहुत बुरा लगता है। इस सब को इंगित करने के लिए धन्यवाद। आपके (4) वें बिंदु के लिए: क्या बैकक्वाटर चाल को करेगा अर्थात ट्रेलिंग न्यूलाइन (एस) को संरक्षित करेगा?
लुई-जैकब लेबेल

@ आपके उत्तर के लिए धन्यवाद। मैंने "कमांड प्रतिस्थापन" के लिए "सबशेल" बदल दिया। वैसे, मुझे आश्चर्य है कि दोनों के बीच सटीक अंतर क्या है।
लुई-जैकब लेबेल

नहीं, backquotes (backticks) के रूप में अच्छी तरह से newline वर्ण अनुगामी पट्टी।
कामिल मैकियोरोस्की

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