खाली लाइनों को हटाने के लिए पाठ फ़ाइल को फ़िल्टर करने का एक अच्छा तरीका क्या है?


11

मेरे पास .csv फ़ाइल (एक मैक पर) जिसमें खाली लाइनों का एक गुच्छा है, जैसे:

"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum 

lorem ipsum ","2","3","4"
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum 

lorem ipsum ","2","3","4"

जिसे मैं इसमें बदलना चाहता हूं:

"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum ","2","3","4"
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum  lorem ipsum ","2","3","4"

मुझे पता है कि एक एक लाइनर होना चाहिए, लेकिन मुझे पता नहीं है कि यह अजीब या सेड है। किसी भी सुझाव बहुत सराहना की!


1
उस नमूने के अनुसार आप वास्तव में खेतों से एम्बेडेड लाइन को हटाना चाहते हैं। क्या वो सही है? दूसरे शब्दों में, 6 इनपुट लाइनें हैं और 2 आउटपुट लाइनें होनी चाहिए?
मैनटवर्क

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

तो आपको जिस चीज़ की ज़रूरत है, वह उद्धरणों के अंदर की नई सुर्खियों को हटा देती है। यह थोड़ा अधिक जटिल होने जा रहा है, क्योंकि आपको मल्टीलाइन रेगेक्स की आवश्यकता है।
जीभपू

जवाबों:


11

ऐसा करने के लिए आप grep का -v(इनवर्ट मैच) मोड का उपयोग कर सकते हैं :

grep -v '^$' old-file.csv > new-file.csv

ध्यान दें कि शेल को पुनर्निर्देशित करने के लिए अलग-अलग फ़ाइलों की आवश्यकता होती है। इनपुट फ़ाइल पढ़ने से पहले आउटपुट फ़ाइल खोली जाती है (और खाली की जाती है)। यदि आपके पास अधिक मैटल हैं (मैक ओएस एक्स पर डिफ़ॉल्ट रूप से नहीं), तो आप इसके spongeआसपास काम करने के लिए उपयोग कर सकते हैं :

grep -v '^$' file.csv | sponge file.csv

लेकिन निश्चित रूप से, आपके पास एक कठिन समय है अगर कुछ गलत हो जाता है।

यदि आपके पास "रिक्त लाइनें" वास्तव में रिक्त स्थान हो सकती हैं (ऐसा लगता है जैसे वे करते हैं), तो आप इसके बजाय इसका उपयोग कर सकते हैं:

egrep -v '^[[:space:]]*$' old-file.csv > new-file.csv

यह खाली लाइनों के साथ-साथ केवल व्हॉट्सएप वाली लाइनों को नजरअंदाज करेगा। आप निश्चित रूप से इस पर एक ही spongeपरिवर्तन कर सकते हैं।


धन्यवाद .... किसी भी खाली लाइनों को नहीं हटाया ... शायद $ $ मेल नहीं खा रहा है? लेकिन मेरे सर्वश्रेष्ठ ज्ञान के लिए लाइनें खाली हैं। याद रखें यह एक सीडी है जो एक्सेल द्वारा बनाया गया है मैक पर ... क्या यह कुछ कहता है? (चिल्लाते हुए भाग न जाएं क्योंकि मैंने कहा था एक्सेल :)
पॉटोसालस

@pitosalas वे शायद खाली लाइनें नहीं हैं। इसे बदलने की कोशिश egrep -v '^[[:space:]]*$'... नोट grep -> egrep और अजीब नए पैटर्न
derobert

काम नहीं किया। दोहरे उद्धरणों के एक समूह को हटा दिया और एक गड़बड़ कर दी ...
पॉटोसलस

@pitosalas मैं अनिश्चित हूं कि यह दोहरे उद्धरण चिह्नों को कैसे हटाएगा। यह केवल व्हाट्सएप को हटाने में सक्षम होना चाहिए। और वास्तव में, कि जब मैं उदाहरण डेटा आप पोस्ट पर उसकी जांच यह क्या करता है ...
derobert

@pitosalas आप जांच कर सकते हैं कि क्या इनमें से कोई भी आदेश कुछ ऐसा है जो उचित दिखता है (जैसा कि अस्पष्टता के विपरीत): iconv -f utf16le file.csv | headयाiconv -f utf16be file.csv | head
अपमानजनक

8

सबसे आसान विकल्प सिर्फ है grep .। यहां, डॉट का अर्थ है "कुछ भी मैच करें", इसलिए यदि रेखा खाली है, तो इसका मिलान नहीं किया जाता है। अन्य रूप में यह पूरी लाइन को प्रिंट करता है।


6

खाली लाइनों को निकालने के लिए जगह में ksh93 साथ,:

sed '/./!d' file 1<>; file

<>;पुनर्निर्देशन ऑपरेटर ksh93 के लिए विशिष्ट है और मानक के रूप में ही है <>कि ksh ट्रंकेटस आदेश के बाद फ़ाइल समाप्त कर दिया है सिवाय ऑपरेटर।

sed '/./!d'लिखने का एक जटिल तरीका है grep ., लेकिन दुर्भाग्यवश GNU grep कम से कम शिकायत करता है अगर उसका स्टडआउट उसी फ़ाइल के रूप में इंगित करता है जो उसका स्टड है। आप कहेंगे कि कोई लिख सकता है:

grep . file | cat 1<>; file

लेकिन दुर्भाग्य से, ksh93 (कम से कम मेरे संस्करण (93u +)) में एक बग है, उस मामले में फ़ाइल को शून्य लंबाई तक छोटा किया जाना प्रतीत होता है।

grep . file | { cat; } 1<>; file

उस बग के आसपास काम करने लगता है, लेकिन अब, यह सेड कमांड की तुलना में कहीं अधिक जटिल है।


कृपया अपने उत्तर को एक अच्छी तरह से स्वरूपित प्रविष्टि में एक त्वरित गाइड के साथ संयोजित करें जब प्रत्येक समाधान को नियोजित किया जाना चाहिए। सभी अलग-अलग समस्याओं के अलग-अलग दृष्टिकोणों ने तैरते हुए जवाबों में एक साथ मिलकर इस सवाल को पढ़ने के लिए एक आपदा बना दिया है।
कालेब

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

बस FYI करें: कोशिश की awk '/./' file 1<>; fileजो काम किया। मेरे लिए, वह भी स्पष्ट हैsed '/./!d'
grebneke

5

यहाँ Perlइसके लिए एक लाइनर है:

perl -pi -e 's/^\s*\n//' yourfile

संपादित करें: नीचे खंड की टिप्पणियों के आधार पर बेहतर कोड।


1
याperl -ni -e '/./ and print' yourfile
derobert

1
@peterph $एक एंकर (अर्थात शून्य-चौड़ाई) है इसलिए यह नई रेखा को बाहर करती है। सुपरफ्लस स्पेस के रूप में, यह कारण है कि मैंने जोड़ा कि /xमैं Perlरीगेक्स में `$ \ 'को इंटरपोल करने की कोशिश नहीं करना चाहता था
जोसेफ आर।

1
आपको यह $दिए जाने की आवश्यकता नहीं है कि आपके पास यह है \n। (वैकल्पिक रूप से - आपको इसकी आवश्यकता नहीं है \n, यह देखते हुए कि आपके पास \s*और है $; लेकिन मुझे लगता s/^\s*\n//है कि यह स्पष्ट कर देता है कि नई रूपरेखा हटा दी गई है।) आपको भी इसकी आवश्यकता नहीं है /m; इस आदेश पर इसका कोई प्रभाव नहीं है। और एक बार जब आप $और अंतरिक्ष से छुटकारा पा लेते हैं , तो आपको इसकी आवश्यकता नहीं होगी /x
12 को बर्बाद करें

1
@ जोसेफ: \nखुद को हटाया जा सकता है; क्या आप ऐसा नहीं कर सकते निकालें है दोनों $ और\n । तो s/^\s*//आपके द्वारा वर्णित समस्या s/^\s*$//होगी , लेकिन ठीक होगी, क्योंकि \s*और $। (जैसा कि आप देख मैं क्या मतलब है?)
ruakh

1
@JosephR: क्या होता है, एक नई रेखा से पहले मेल $ कर सकता है (बशर्ते कि या तो /mध्वज सक्षम हो, या न्यूलाइन स्ट्रिंग, या दोनों का बहुत अंतिम वर्ण है), लेकिन यह स्ट्रिंग के अंत से भी मेल खा सकता है । उदाहरण के लिए, "abc" =~ m/^abc$/सत्य है। के मामले में \s*$, \s*नई लाइन खाने के लिए पर्याप्त लालची है, और फिर $अंत के तार से मेल खाता है। (लेकिन मुझे लगता s/^\s*\n//है कि स्पष्ट है, वैसे भी, तो आपका जवाब अभी ठीक है जैसा कि अभी है।)
राखी

5

आपके प्रश्न के लिए टिप्पणियों में स्पष्टीकरण के आधार पर, कुछ इस तरह:

awk -v RS= -v ORS= 1

आप जो चाहते हैं वह कर सकते हैं।

एक खाली रिकॉर्ड विभाजक एक विशेष मामला है जो बताता है awkकि रिकॉर्ड पैराग्राफ होने हैं (खाली लाइनों के अनुक्रम द्वारा अलग किए गए)। आउटपुट रिकॉर्ड विभाजक को रिक्त स्ट्रिंग में सेट करने के साथ-साथ इसका मतलब है कि उन पैराग्राफ (विभाजक के बिना) की सामग्री को संक्षिप्त किया जाना है। हर रिकॉर्ड को छापने के लिए 1सिर्फ एक सही शर्त है।

हालाँकि, अनुगामी न्यूलाइन को छोड़ दिया जाएगा, इसलिए आप ऐसा कर सकते हैं:

awk -v RS= -v ORS= '1;END{if (NR) printf "\n"}'

3

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

require 'csv'
c = CSV.open("outfile1.csv", "w")
CSV.foreach("data.csv", :encoding => 'windows-1251:utf-8') do |row|
  row = row.map { |a| a.class == String ? a.gsub(/\r/, '') : a}
  c << row
end
c.close

मदद करने के लिए सभी को धन्यवाद!


2
awk '
    length == 0 {next} 
    /^[^"]/ && /"$/ {print; next} 
    {printf("%s", $0)}
' filename

पैदा करता है

"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum ","2","3","4"
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum ","2","3","4"

2

मैं पर एक संभव समाधान के लिए एक विचार पाया stackoverflow

sed -i ':a;N;$!ba;s/[^"]\n\s*\n/ /g' file.csv

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

इस अभिव्यक्ति के आंतरिक कामकाज के बारे में एक अच्छी व्याख्या उत्तर में दी गई है, मैंने इसे केवल उन लाइनों की तलाश के लिए संपादित किया है जो एक "( [^"]\n) के साथ समाप्त नहीं होती हैं ।


1

यदि, आपकी स्वयं की प्रतिक्रिया से, आप उद्धृत स्ट्रिंग्स के अंदर निहित नईलाइन वर्णों को निकालना चाहते हैं, तो आप ऐसा कर सकते हैं:

 perl -0777 -pe 's/".*?"/$_=$&;s:\n::g;$_/gse'

तुम भी उपयोग पर्ल का इस्तेमाल कर सकते हैं -iफ़ाइलों को संपादित करने के लिए ध्वज जगह में

 perl -0777 -pe 's/".*?"/$_=$&;s:\n::g;$_/gse' file1 file2...

या GNU awk के साथ:

 awk -v RS=\" 'NR%2==0 {gsub("\n","")}; {printf "%s", $0 RT}'

या:

 awk -vRS=\" '1-NR%2{gsub("\n","")}{ORS=RT}1'

(यदि आप कम से कम एक के लिए प्रतिस्पर्धा कर रहे हैं)

ध्यान दें कि उन लोगों का मानना ​​है कि इनपुट में कोई बची हुई दोहरी बोली वर्ण नहीं हैं ।


0

यह प्रभाव की तरह दिखता है कि आप खाली लाइनों को हटाने से अधिक चाहते हैं, लेकिन 2 या अधिक न्यूलाइन वर्णों के प्रत्येक अनुक्रम को हटा दें।

जिसे आप पर्ल के साथ कर सकते हैं:

perl -0777 -pe 's/\n{2,}//gs' file

तुम भी उपयोग पर्ल का इस्तेमाल कर सकते हैं -iफ़ाइलों को संपादित करने के लिए ध्वज जगह में

perl -0777 -pi -e 's/\n{2,}//gs' file1 file2...

0

इसमें खाली लाइनों को हटाने का एक छोटा तरीका है AWK:

awk 'NF' file

लेकिन आप चाहते हैं कि उत्पादन प्राप्त करने के लिए, सभी की जरूरत है एक सरल एक लाइनर है:

awk 'NF {printf("%s ", $0); i++;} !(i % 2) {printf("\n");}' file

व्याख्या

में AWK, एक खाली रेखा का मतलब है कि पंक्ति / रिकॉर्ड का कोई क्षेत्र नहीं है, अर्थात, NF(फ़ील्ड की संख्या) चर शून्य है। ऊपर एक लाइनर केवल तभी निष्पादित होगा जब NF > 0सभी लाइनों को प्रिंट किया जाएगा , लेकिन खाली वाले।

i++गैर खाली लाइनों काउंटर है।

!(i % 2)अपना इच्छित उत्पादन, यह है कि के रास्ते में लगातार दो गैर खाली लाइनों मुद्रित करने के लिए प्रयोग किया जाता है, हर बार 2 की एक बहु पाया जाता है, moduloबयान !(i % 2)पैदावार 1, क्या दो गैर खाली लाइनों के संयोजन समाप्त हो जाता है।


मेरी गलती! माफ़ करना। मैंने उनका पूरा सवाल और वांछित आउटपुट नहीं पढ़ा। अब जवाब तय है। धन्यवाद। :-)
मार्सेलो अगस्टो

0

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

ex -sc v/./d -cx b.csv
  1. v/./ खाली लाइनें खोजें

  2. d हटाना

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

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