टी -a फ़ाइल को फिर से नहीं बनाता है


7

मैं रास्पबेरी पाई 3 डेबियन नवीनतम रिलीज पर निम्नलिखित कमांड चला रहा हूं:

cat /dev/ttyUSB0 | tee -a /media/pi/KINGSTON/klima.out | grep -F $ | tee -a /media/pi/KINGSTON/log

आदेश ठीक काम करता है और उसे वही करना चाहिए जो उसे करना चाहिए; हालाँकि, जब मैं klima.outफ़ाइल को (मैन्युअल रूप से या CRON द्वारा) डिलीट करता हूं, तो यह दोबारा नहीं बनाया जाता है। आदेश चलता रहता है, लॉग फ़ाइल को जोड़ा जाता है, लेकिन klima.outफ़ाइल वापस नहीं आती है। (भी कोई बफरिंग नहीं है)। मैं इसे सभी सीमाओं पर बढ़ने नहीं देने के लिए सप्ताह में एक बार इसे हटाना चाहता हूं। कोई सुझाव?


1
@ कुसलानंद, केवल rc/ esया fishगोले में। बॉर्न-जैसे गोले और csh- जैसे गोले ठीक होना चाहिए।
स्टीफन चेज़लस

1
कुसलानंद का जवाब सही है; ध्यान दें कि यदि आपका स्रोत डिवाइस के बजाय एक बढ़ती हुई लॉग फ़ाइल थी, तो आप "टेल-ऑफ़" करना चाह सकते हैं ताकि आप पहले से संसाधित न होने वाली चीज़ों को फिर से कैट न करें।
TOOGAM

1
ध्यान रखें कि फ़ाइल को हटाना (जैसे rm) अनिवार्य रूप से एक निर्देशिका पर एक संपादित ऑपरेशन है। यह निर्देशिका से फ़ाइल की ओर इशारा करते हुए प्रविष्टि को हटाता है। फ़ाइल ही हटा दी जाएगी जब कुछ भी उपयोग नहीं कर रहा है; लेकिन teeइसका उपयोग कर रहा है।
रीइनियरिएपोस्ट

यह एक बेकार उपयोग की तरह दिखता है cat। इसके बजाय, tee < /dev/ttyUSB0 -a ... | ...वही काम करेगा, लेकिन teeएक पाइप के बजाय सीधे चार देव से पढ़ेगा cat
पीटर कॉर्ड्स

जवाबों:


13

यदि आप फ़ाइल ब्लॉक को पुनर्प्राप्त करना चाहते हैं, तो आपको फ़ाइल को खाली करना होगा, इसे अनलिंक नहीं करना चाहिए:

यह पोर्टेबल तरीका अधिकांश गोले के साथ काम करना चाहिए:

: > /media/pi/KINGSTON/klima.out

फ़ाइल को अनलिंक करना (यानी rm) निर्देशिका प्रविष्टि को हटा रहा है लेकिन फ़ाइल सामग्री (इनोड) को तब तक प्रभावित नहीं करता है जब तक फ़ाइल पाठकों या लेखकों द्वारा खुली रखी जाती है।


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

3
:शून्य कमांड है, अर्थात यह कुछ खास नहीं करता है। यहां उपयोग की जाने वाली एकमात्र विशेषता शेल द्वारा प्रदान की गई है: पुनर्निर्देशन फ़ाइल को खाली सामग्री पर रीसेट कर रहा है।
जूलियाग्रे

3
@jlliagre आप दोनों बिंदुओं पर पूरी तरह से सही हैं।
Kusalananda

1
@ Björn वास्तव में, हालांकि कड़ाई से समकक्ष नहीं echo ""है, फ़ाइल के लिए एक बाइट लिखेंगे। ध्यान दें कि echoअकेले के रूप में ही करता है echo ""
जेलीगेरे

1
@ ब्योर्न खैर, echo -nव्यवहार को परिभाषित किया गया है। शेल के आधार पर, यह कमांड फ़ाइल सामग्री -nको पूरी तरह से रौंदने के बजाय स्ट्रिंग के साथ बदल सकती है। "कुछ भी नहीं" लिखने का एक पोर्टेबल तरीका है printf ""
जलीगेरे

19

मैं मान रहा हूं कि आपकी पाइपलाइन लंबे समय से चल रही है और जब आप चल रहे हैं तो लॉग फाइल को हटाने की कोशिश कर रहे हैं।

जब आप फ़ाइल को हटाते हैं, तो यह teeप्रक्रिया अभी भी लिखने के लिए खुली है, जिसका अर्थ है कि डिस्क स्थान को सिस्टम में वापस नहीं सौंपा गया है। ऐसा तब तक नहीं होगा जब तक कि फाइल को बंद करने वाले सभी ओपन फाइल डिस्क्रिप्टर बंद न हो जाएं।

किसी फ़ाइल को हटाने के लिए लिखना पूरी तरह से ठीक है, जब तक कि फ़ाइल डिस्क्रिप्टर को हटाने से पहले आवंटित किया गया था।

आपको फ़ाइल को फिर से बनाने के लिए पाइपलाइन को फिर से शुरू करना होगा, और पुरानी (अब नाम रहित) लॉग फ़ाइल द्वारा ली गई जगह को पुनः प्राप्त करने की अनुमति देना होगा।

पाइप लाइन को पुनः आरंभ करने से बचने के लिए, आप चुन सकते हैं काटना फ़ाइल, यानी इसे हटाने के बिना शून्य हो जाने पर इसके आकार ट्रिम। यह teeफ़ाइल को फिर से खोलने के लिए बिना इसे जारी रखने की अनुमति देगा ।

किसी फ़ाइल को काट-छाँट किया जा सकता है , जैसे कि उसके उत्तर में दिखाए गए jlliagre , या truncate(गैर-मानक उपयोगिता जो GNU कोरुटिल्स का हिस्सा है) का उपयोग करके :

truncate -s 0 /media/pi/KINGSTON/klima.out

उस उपयोगिता के बारे में अधिक जानकारी के लिए मैनुअलtruncate देखें ।


जब तक फ़ाइल डिस्क्रिप्टर को हटाए जाने से पहले आवंटित किया गया था । वास्तव में, आप पहले से हटाए गए-लेकिन-अभी भी खुले फ़ाइलों के माध्यम से नए फ़ाइल डिस्क्रिप्टर प्राप्त कर सकते हैं /proc/pid/fd। यह भी उन के माध्यम से लिखने के लिए पूरी तरह से ठीक है, भी। तो वास्तव में, जब तक आपके पास एक ओपन फाइल डिस्क्रिप्टर होता है, उस इनोड के लिए निर्देशिका प्रविष्टियों की संख्या बहुत अधिक अप्रासंगिक होती है।
पीटर कॉर्डेस

काट-छाँट करने के बाद, अभी भी खुले fd के लिए अगला लिखने के परिणामस्वरूप एक विरल फ़ाइल होगी, इसलिए हाँ यह स्थान को पुनर्प्राप्त करता है लेकिन आपके पास नए पाठ से पहले शून्य के कई बाइट्स हैं, क्योंकि यह पहले से ही फ़ाइल की स्थिति को रीसेट नहीं करता है -ठंडों का सिलसिला। (और कुछ फाइल सिस्टम विरल फ़ाइलों का समर्थन नहीं करते हैं, जैसे FAT या HFS +, इसलिए अगला लेखन वास्तव में शून्य लिखेगा)। वैसे भी, मुझे नहीं लगता कि इसके आसपास कोई ऐसा तरीका है (जो एक ptrace / डिबगर हैक के अलावा है जो फ़ाइल की स्थिति के teeसाथ-साथ truncating को रीसेट करता है )।
पीटर कॉर्ड्स

वैसे भी, आप करंट लेन से केवल एक छेद बाहर निकाल सकते हैं fallocate -p, लेकिन फिर आपको सही लंबाई की आवश्यकता होती है और यह सब आपको एक इनोड अपडेट को बचाने में मदद करता है (लंबाई को शून्य पर सेट करने की आवश्यकता नहीं है)।
पीटर कॉर्ड्स

@PeterCordes मैंने इसका परीक्षण किया और यह एक विरल फ़ाइल बनाने के लिए प्रतीत नहीं होता है। एक 100M फ़ाइल को एपेंड मोड में खोला गया, फिर ऊपर के रूप में छोटा किया गया। इसका अगला लेखन अब खाली फ़ाइल की शुरुआत में होगा, कुछ विरल अंतराल के बाद नहीं, जहाँ तक मैं देख सकता हूँ।
Kusalananda

1
@PeterCordes आह, हाँ, यदि आप उपयोग करते हैं >, लेकिन यदि आप उपयोग नहीं करते हैं >>या, जैसा कि ओपी कर रहा था, तो tee -a। एपेंड मोड में लिखना हमेशा फाइल के तार्किक छोर में जुड़ जाता है, जबकि एपेंड मोड का उपयोग नहीं करने पर अंतिम लिखने के बाद भौतिक स्थान पर लिखना होगा।
Kusalananda

4

आपको समझ नहीं आ रहा है कि सिस्टम फाइलों को कैसे संभाल रहा है।

आप फ़ाइल प्रविष्टि को हटाते हैं, लेकिन फ़ाइल तब भी मौजूद रहती है जब तक प्रोग्राम उस पर एक हैंडल रखता है। इसलिए टी को कभी सूचित नहीं किया जाता है प्रविष्टि हटा दी गई थी और यह अभी भी फ़ाइल को लिखता है!

एक अद्वितीय फ़ाइल में हार्ड लिंक (ln कमांड द्वारा बनाई गई) के लिए कई प्रविष्टियाँ हो सकती हैं।

आप अपने स्वयं के संस्करण को लिख सकते हैं जो फ़ाइल को लिखने वाली प्रत्येक पंक्ति पर फ़ाइल को बंद और खोल देता है, लेकिन यह बहुत कम प्रदर्शन वाला होगा क्योंकि यह बहुत सारे सिस्टम कॉल उत्पन्न करेगा।

यहाँ एक शेल-फंक्शन है जो इसके इनपुट को कई फाइलों में विभाजित करेगा:

splitSizeInKio=100

splitInput(){
    local PS4='+splitInput+ '
    set -x
    local i=0
    local fname="$1"
    local ii

    while true
    do if [ $i -lt 10 ]
       then ii=0$i
       else ii=$i
       fi
       local outfile="$fname".$ii
       dd of="$outfile" bs=1024 count=$splitSizeInKio
       i=$((i+1))
    done
}

(यदि आप "dd" के बजाय "हेड" का उपयोग कर सकते हैं यदि आप एक आकार के बजाय कई पंक्तियों पर फैलाए जाते हैं।)

बैश के साथ, आप इस तरह से "प्रक्रिया प्रतिस्थापन" का उपयोग कर सकते हैं:

prog1 | tee >( splitInput somefilename ) | prog2

1
आपका स्प्लिटइन्पुट ठीक उपयोग करके काम कर सकता है dd, क्योंकि यह जानता है कि " स्टड " से कितने बाइट्स पढ़ने के लिए बिल्कुल ठीक है, लेकिन headबफरिंग के कारण भ्रष्ट डेटा के परिणामस्वरूप बहुत अधिक संभावना है।
बेनगोल्डबर्ग

हाँ, headयह लिखने से स्टड से अधिक डेटा पढ़ेगा, क्योंकि यह एक बार में 1 चार्ट नहीं पढ़ता है। और यह किसी भी ओवर-रीड को "वापस डालने" की कोशिश नहीं करता है जो उस लाइनों की संख्या से परे है जो इसे ढूंढ रहा था (यदि यह पाइप पर भी संभव है)।
पीटर कॉर्डेस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.