EOF पर कई नए लिंक कैसे निकालें?


25

मेरे पास ऐसी फाइलें हैं जो एक या एक से अधिक न्यूलाइन्स में समाप्त होती हैं और केवल एक न्यूलाइन में समाप्त होनी चाहिए। मैं बैश / यूनिक्स / जीएनयू टूल के साथ कैसे कर सकता हूं?

उदाहरण खराब फ़ाइल:

1\n
\n
2\n
\n
\n
3\n
\n
\n
\n

उदाहरण के लिए सही फ़ाइल:

1\n
\n
2\n
\n
\n
3\n

दूसरे शब्दों में: ईओएफ और फ़ाइल के अंतिम गैर-न्यूलाइन चरित्र के बीच एक नई रूपरेखा होनी चाहिए।

संदर्भ कार्यान्वयन

फ़ाइल सामग्री पढ़ें, एक नई पंक्ति को तब तक काटें जब तक कि आगे की दो नई पंक्तियाँ न हों, इसे वापस लिखें:

#! /bin/python

import sys

with open(sys.argv[1]) as infile:
    lines = infile.read()

while lines.endswith("\n\n"):
    lines = lines[:-1]

with open(sys.argv[2], 'w') as outfile:
    for line in lines:
        outfile.write(line)

स्पष्टीकरण: निश्चित रूप से, पाइपिंग की अनुमति है, अगर वह अधिक सुरुचिपूर्ण है।

जवाबों:


16
awk '/^$/ {nlstack=nlstack "\n";next;} {printf "%s",nlstack; nlstack=""; print;}' file

2
+1: awk के समाधान (लगभग) हमेशा सुरुचिपूर्ण और पठनीय होते हैं!
ओलिवियर दुलक

@OlivierDulac वास्तव में। जब मैंने sedप्रस्ताव देखा तो मुझे लगा कि OMG ...
Hauke ​​Laging

1
यह होमब्रे से नवीनतम उपलब्ध awk का उपयोग करके OSX Mavericks पर काम नहीं करता है। यह त्रुटियों के साथ awk: illegal statementbrew install mawkऔर mawkहालांकि काम करने के लिए आदेश बदल रहा है ।
tjmcewan

@ गन मुझे भी सवाल समझ में नहीं आता ...
Hauke ​​Laging

कोई भी awk जो स्क्रिप्ट में काम नहीं करता है, एक बुरी तरह से टूटी हुई awk है - इसका उपयोग करना बंद करें और एक नई awk प्राप्त करें क्योंकि यदि यह ऐसा नहीं कर सकता है, तो कौन जानता है कि इसके पास और क्या टूटना है।
एड मॉर्टन

21

से उपयोगी एक-पंक्ति स्क्रिप्ट के लिए sed

# Delete all trailing blank lines at end of file (only).
sed -e :a -e '/^\n*$/{$d;N;};/\n$/ba' file

4
धन्यवाद, मैंने कई फ़ाइलों के लिए इसे करने के लिए निम्नलिखित का उपयोग किया: find . -type f -name '*.js' -exec sed --in-place -e :a -e '/^\n*$/{$d;N;};/\n$/ba' {} \;
jakub.g

@ जगह में jakub.g और पुनरावर्ती वास्तव में मैं क्या जरूरत है। धन्यवाद।
बटलर बटुक

@ Jakub.g की उत्कृष्ट टिप्पणी को जोड़ने के लिए आप OS X पर इस तरह से कमांड दे सकते हैं:find . -type f -name '*.js' -exec sed -i '' -e :a -e '/^\n*$/{$d;N;};/\n$/ba' {} \;
davejagoda

18

चूंकि आपके पास पहले से ही अधिक उपयुक्त उपकरणों के साथ उत्तर हैं, जो कि sed और awk; आप इस तथ्य का लाभ उठा सकते हैं कि $(< file)रिक्त लाइनों को पीछे छोड़ते हुए स्ट्रिप्स।

a=$(<file); printf '%s\n' "$a" > file

वह सस्ते हैक, खाली लाइनों को हटाने के लिए काम नहीं करेगा जिसमें रिक्त स्थान या अन्य गैर-मुद्रण वर्ण हो सकते हैं, केवल खाली लाइनों को हटाने के लिए। यह भी काम नहीं करेगा अगर फ़ाइल में अशक्त बाइट्स हों।

बाश और zsh के अलावा अन्य गोले में, के $(cat file)बजाय का उपयोग करें $(<file)


+1 इंगित करने के लिए कि मेरे लिए बग क्या दिखता है: $ (<फ़ाइल) वास्तव में फ़ाइल नहीं पढ़ रही है? यह नए सिरे से पीछे क्यों हटता है? (यह करता है, मैं सिर्फ परीक्षण किया, यह इंगित करने के लिए धन्यवाद!)
ओलिवियर दुलक

2
@OlivierDulac नए समाचारों $()को पीछे छोड़ता है। यह एक डिजाइन निर्णय है। मुझे लगता है कि यह अन्य तारों में एकीकरण को आसान बना देगा: echo "On $(date ...) we will meet."नई लाइन के साथ बुराई होगी जो अंत में लगभग हर शेल कमांड आउटपुट करती है।
हॉक लैगिंग

@ हॉकिंग: अच्छी बात है, यह शायद उस व्यवहार का स्रोत है
ओलिवियर दुलक

मैंने खाली फाइलों में "\ n" को जोड़ने से बचने के लिए एक विशेष मामला जोड़ा [[ $a == '' ]] || printf '%s\n' "$a" >"$file":।
davidchambers

किसी फ़ाइल के शुरू होने से कई नए समाचारों को हटाने के लिए, इस प्रक्रिया में tac डालें (मैं मैक पर gnu coreutils का उपयोग करता हूं, इसलिए मेरे लिए gtac):a=$(gtac file.txt); printf '%s\n' "$a" | gtac > file.txt
r_alex_hall


4

इस प्रश्न को साथ टैग किया गया है , लेकिन किसी ने भी edसमाधान का प्रस्ताव नहीं किया है ।

यहां एक है:

ed -s file <<'ED_END'
a

.
?^..*?+1,.d
w
ED_END

या, समकक्ष,

printf '%s\n' a '' . '?^..*?+1,.d' w | ed -s file

ed स्टार्टअप पर डिफ़ॉल्ट रूप से आपको संपादन बफ़र की अंतिम पंक्ति में स्थान देगा।

पहला कमांड ( a) बफर के अंत में एक खाली लाइन जोड़ता है (संपादन स्क्रिप्ट में खाली लाइन यह रेखा है, और डॉट ( .) केवल कमांड मोड में वापस आने के लिए है)।

दूसरी कमांड ( ?) निकटतम पिछली पंक्ति को ढूंढती है जिसमें कुछ (यहां तक ​​कि सफेद-अंतरिक्ष वर्ण) होते हैं, और फिर अगली पंक्ति से बफर के अंत तक सब कुछ हटा देता है।

तीसरी कमांड ( w) डिस्क पर वापस फ़ाइल लिखती है।

जोड़ी गई खाली लाइन शेष फ़ाइल को उस स्थिति में हटाए जाने से बचाती है जब मूल फ़ाइल के अंत में कोई खाली लाइनें नहीं होती हैं।


3

यहाँ एक पर्ल समाधान है जिसे एक बार में एक लाइन से अधिक मेमोरी में पढ़ने की आवश्यकता नहीं है:

my $n = 0;
while (<>) {
    if (/./) {
        print "\n" x $n, $_;
        $n = 0;
    } else {
        $n++;
    }
}

या, एक-लाइनर के रूप में:

perl -ne 'if (/./) { print "\n" x $n, $_; $n = 0 } else { $n++ }'

यह फ़ाइल को एक बार में एक पंक्ति पढ़ता है और यह देखने के लिए कि क्या कोई गैर-नई वर्ण है, प्रत्येक पंक्ति की जाँच करता है। यदि ऐसा नहीं होता है, तो यह एक काउंटर बढ़ाता है; यदि ऐसा होता है, तो यह काउंटर द्वारा इंगित नई संख्याओं की संख्या को प्रिंट करता है, उसके बाद लाइन द्वारा ही, और फिर काउंटर को रीसेट करता है।

तकनीकी रूप से, यहां तक ​​कि स्मृति में एक भी लाइन बफरिंग अनावश्यक है; फिक्स्ड-लेंथ चंक्स में फाइल को पढ़कर और स्टेट मशीन का उपयोग करके कैरेक्टर द्वारा इसे प्रोसेस करके मेमोरी की निरंतर मात्रा का उपयोग करके इस समस्या को हल करना संभव होगा। हालांकि, मुझे संदेह है कि ठेठ उपयोग के मामले के लिए अनावश्यक रूप से जटिल होगा।


1

यदि आपकी फ़ाइल मेमोरी में खिसकने के लिए काफी छोटी है, तो आप इसका उपयोग कर सकते हैं

perl -e 'local($/);$f=<>; $f=~s/\n*$/\n/;print $f;' file

0

अजगर में (मुझे पता है कि यह वह नहीं है जो आप चाहते हैं, लेकिन यह बहुत बेहतर है क्योंकि इसे अनुकूलित किया गया है, और बैश संस्करण के लिए एक प्रस्तावना) फ़ाइल को फिर से लिखे बिना और सभी फ़ाइल को पढ़े बिना (जो कि एक अच्छी बात है अगर फ़ाइल बहुत बड़ा):

#!/bin/python
import sys
infile = open(sys.argv[1], 'r+')
infile.seek(-1, 2)
while infile.read(1) == '\n':
  infile.seek(-2, 1)
infile.seek(1, 1)
infile.truncate()
infile.close()

ध्यान दें कि यह उन फ़ाइलों पर काम नहीं करता है जहाँ EOL वर्ण '\ n' नहीं है।


0

एक बैश संस्करण, अजगर एल्गोरिथ्म को लागू करना, लेकिन कम कुशल क्योंकि इसमें कई प्रक्रियाओं की आवश्यकता होती है:

#!/bin/bash
n=1
while test "$(tail -n $n "$1")" == ""; do
  ((n++))
done
((n--))
truncate -s $(($(stat -c "%s" "$1") - $n)) "$1"

0

यह टाइप करने के लिए त्वरित है, और, यदि आप sed जानते हैं, तो याद रखना आसान है:

tac < file | sed '/[^[:blank:]]/,$!d' | tac

यह एलेक्सी, ऊपर और टैक (उल्टा) द्वारा संदर्भित, सेड के लिए उपयोगी एक लाइन स्क्रिप्ट से प्रमुख रिक्त लाइनों को हटाने के लिए sed स्क्रिप्ट का उपयोग करता है ।

एक त्वरित परीक्षण में, एक 18 एमबी, 64,000 लाइन फ़ाइल पर, एलेक्सी का दृष्टिकोण तेज था, (0.036 बनाम 0.046 सेकंड)।

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