लिनक्स: एक ही समय में इनपुट और आउटपुट के रूप में फ़ाइल का उपयोग कैसे करें?


55

मैंने बस निम्नलिखित को bash में चलाया है:

uniq .bash_history > .bash_history

और मेरी इतिहास फ़ाइल पूरी तरह से खाली हो गई।

मुझे लगता है कि मुझे लिखने से पहले पूरी फाइल को पढ़ने का एक तरीका चाहिए। कैसे किया जाता है?

पुनश्च: मैं स्पष्ट रूप से एक अस्थायी फ़ाइल का उपयोग करने के बारे में सोचा था, लेकिन मैं एक और अधिक सुंदर समाधान की तलाश कर रहा हूं।


ऐसा इसलिए है क्योंकि फाइलें दाईं से बाईं ओर खुलती हैं। यह भी देखें stackoverflow.com/questions/146435/...
WheresAlice

आपको आउटपुट को उसी निर्देशिका में एक नई फ़ाइल में लिखना होगा और पुरानी फ़ाइल के शीर्ष पर उसका नाम बदलना होगा। किसी अन्य दृष्टिकोण से आपके डेटा को खोने का जोखिम होगा अगर यह आधे रास्ते से बाधित हो। कुछ उपकरण आपसे इस चरण को छिपा सकते हैं।
कास्परड

या, bashयदि आप HISTCONTROL को अनदेखा करने के लिए सेट करते हैं, तो इसके इतिहास में लगातार कोई कमी नहीं होगी; मैनपेज देखें।
dave_thompson_085

जवाबों:


49

मैं moreutilssponge से उपयोग करने की सलाह देता हूं । मैनपेज से:

DESCRIPTION
  sponge  reads  standard  input  and writes it out to the specified file. Unlike
  a shell redirect, sponge soaks up all its input before opening the output file.
  This allows for constructing pipelines that read from and write to the same 
  file.

इसे अपनी समस्या पर लागू करने के लिए, प्रयास करें:

uniq .bash_history | sponge .bash_history

6
यह बिल्ली की तरह है, लेकिन चूसने की क्षमता के साथ: D
MilliaLover

77

मैं बस एक और उत्तर देना चाहता था जो सरल है, और स्पंज का उपयोग नहीं करता है (क्योंकि यह अक्सर हल्के वातावरण में शामिल नहीं होता है)।

echo "$(uniq .bash_history)" > .bash_history

वांछित परिणाम होना चाहिए। सबस्क्रिप्शन को निष्पादित होने से पहले .bash_history को लेखन के लिए खोल दिया जाता है। जैसा कि फिल पी के जवाब में बताया गया है, जब तक .bash_history मूल कमांड में पढ़ा जाता है, तो यह पहले से ही '>' ऑपरेटर द्वारा काट दिया गया है।


15
मैं आम तौर पर उन उत्तरों का प्रशंसक नहीं हूं जो एक प्राचीन प्रश्न को मिटा देते हैं, जिसमें पहले से ही मान्य, स्वीकृत उत्तर है - लेकिन यह सुरुचिपूर्ण, अच्छी तरह से लिखा गया है, और इसकी आवश्यकता (हल्के वातावरण) के लिए एक मजबूत तर्क देता है; मेरे लिए, यह वास्तव में उत्तरों के मौजूदा सेट में कुछ जोड़ता है। एसएफ, हार्ट में आपका स्वागत है (आप यहां एक महीने में आए हैं, लेकिन मुझे लगता है कि यह आपकी पहली महत्वपूर्ण पोस्टिंग है)। मुझे आशा है कि आप इस तरह से और अधिक जवाब पढ़ने के लिए!
मध्याह्न

4
यह सबसे अच्छा उपाय है। मुझे $()कुछ बचने वाले मुद्दों के कारण बैकटिक्स के बजाय एक सबस्क्रिप्शन का उपयोग करना पड़ा ।
CMCDragonkai

3
मुझे आश्चर्य हो रहा है कि क्या यह समाधान बड़ी फ़ाइलों के लिए, कहता है ... 20 या 50 जीबी।
अमित नायडू

1
यह वास्तव में स्वीकार जवाब होना चाहिए।
मैक्सवेल

1
मैंने echo "$(fmt -p '# ' -w 50 readme.txt)" > readme.txtआज करने के लिए इस उत्तर का उपयोग किया । एक सुरुचिपूर्ण समाधान के लिए लंबे समय से खोज कर रहा था। बहुत धन्यवाद, @ सार्थक सिम्हा!
12

12

समस्या यह है कि आपका शेल कमांड चलाने से पहले कमांड पाइपलाइन स्थापित कर रहा है। यह "इनपुट और आउटपुट" की बात नहीं है, यह है कि फ़ाइल की सामग्री पहले से ही uniq भी चलती है। यह कुछ इस तरह है:

  1. खोल >, इसे रौंदते हुए, लेखन के लिए आउटपुट फ़ाइल खोलता है
  2. शेल में आउटपुट के लिए फ़ाइल-डिस्क्रिप्टर 1 (stdout के लिए) का उपयोग किया जाता है
  3. खोल uniq निष्पादित करता है, शायद कुछ ऐसा है जैसा execlp ("uniq", "uniq", ".bash_history", NULL)
  4. uniq चलाता है, खुलता है .bash_history और वहाँ कुछ भी नहीं पाता है

इन-प्लेस संपादन और अस्थायी फ़ाइल उपयोग सहित विभिन्न समाधान हैं, जिनका अन्य लोग उल्लेख करते हैं, लेकिन समस्या को समझना महत्वपूर्ण है, वास्तव में क्या गलत है और क्यों हो रहा है।


9

ऐसा करने के लिए एक और चाल, बिना उपयोग के sponge, निम्नलिखित आदेश है:

{ rm .bash_history && uniq > .bash_history; } < .bash_history

यह backreference.org पर फ़ाइलों के उत्कृष्ट लेख "इन-प्लेस" के संपादन में वर्णित धोखा देती है ।

यह मूल रूप से पढ़ने के लिए फ़ाइल खोलता है, फिर इसे "हटाता है"। यह वास्तव में हटाया नहीं गया है, हालांकि: एक खुली फ़ाइल डिस्क्रिप्टर है जो इसे इंगित करता है, और जब तक यह खुला रहता है, तब भी फ़ाइल चारों ओर है। फिर यह उसी नाम से एक नई फ़ाइल बनाता है और इसके लिए अद्वितीय लाइनें लिखता है।

इस समाधान का नुकसान: यदि uniqकिसी कारण से विफल रहता है, तो आपका इतिहास समाप्त हो जाएगा।



3

यह sedस्क्रिप्ट आसन्न डुप्लिकेट को निकाल देती है। -iविकल्प के साथ , यह जगह में संशोधन करता है। यह sed infoफ़ाइल से है:

sed -i 'h;:b;$b;N;/^\(.*\)\n\1$/ {g;bb};$b;P;D' .bash_history

sed अभी भी अस्थायी फ़ाइल का उपयोग करता है, straceचित्रण के साथ एक उत्तर जोड़ा (ऐसा नहीं है कि यह वास्तव में मायने रखता है) :-)
काइल ब्रांट

3
@ केश: सच, लेकिन "दृष्टि से बाहर, मन से बाहर"। व्यक्तिगत रूप से, मैं स्पष्ट अस्थायी फ़ाइल का उपयोग करूँगा, क्योंकि कुछ ऐसा है जो process input > tmp && mv tmp inputबहुत आसान है और sedकेवल एक अस्थायी फ़ाइल से बचने के लिए प्रवंचना का उपयोग करने की तुलना में अधिक पठनीय है और यह मेरे मूल को अधिलेखित नहीं करेगा यदि यह विफल हो जाता है (मुझे नहीं पता कि यदि sed -iमैं इनायत से विफल रहता हूं - तो मैं करूंगा हालांकि ऐसा लगता है)। इसके अलावा, बहुत सी चीजें हैं जो आप आउटपुट-टू-टेम्प-फाइल विधि के साथ कर सकते हैं जो इस sedस्क्रिप्ट की तुलना में कुछ भी शामिल किए बिना इन-प्लेस नहीं किया जा सकता है । मुझे पता है कि आप यह सब जानते हैं, लेकिन इससे कुछ दर्शकों को फायदा हो सकता है।
डेनिस विलियमसन

3

एक दिलचस्प tidbit के रूप में, sed एक अस्थायी फ़ाइल का उपयोग करता है (यह सिर्फ आपके लिए करता है):

$ strace sed -i 's/foo/bar/g' foo    
open("foo", O_RDONLY|O_LARGEFILE)       = 3
...
open("./sedPmPv9z", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600) = 4
...
read(3, "foo\n"..., 4096)               = 4
write(4, "bar\n"..., 4)                 = 4
read(3, ""..., 4096)                    = 0
close(3)                                = 0
close(4)                                = 0
rename("./sedPmPv9z", "foo")            = 0
close(1)                                = 0
close(2)                                = 0

विवरण:
tempfile ./sedPmPv9zfd 4 हो जाता है, और fooफ़ाइलें fd 3 हो जाती हैं। रीड ऑपरेशन्स fd 3 पर हैं, और fd 4 पर लिखता है (अस्थायी फ़ाइल)। फ़ू फ़ाइल को फिर से कॉल नाम में अस्थायी फ़ाइल के साथ अधिलेखित कर दिया जाता है।



0

एक अस्थायी फ़ाइल बहुत अधिक होती है, जब तक कि प्रश्न में आदेश जगह संपादन में समर्थन करने के लिए होता है ( uniqनहीं - कुछ sedएस करते हैं ( sed -i))।


0

आप पूर्व मोड में विम का उपयोग कर सकते हैं:

ex -sc '%!uniq' -cx .bash_history
  1. % सभी लाइनों का चयन करें

  2. ! चलाने के आदेश

  3. x सहेजें और बंद करें


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.