किसी फ़ाइल की केवल प्रत्येक nth लाइन को कैसे रखें


71

मुझे एक बहुत बड़ा CSV फ़ाइल (75MB) मिला है। मैं सिर्फ इसका एक ग्राफ बनाने की कोशिश कर रहा हूं, इसलिए मुझे वास्तव में सभी डेटा की आवश्यकता नहीं है।

रिकॉर्डिंग: मैं n लाइन्स हटाना चाहता हूँ, फिर एक लाइन रखूँगा, फिर n लाइन्स डिलीट करूँगा, इत्यादि।

तो अगर फ़ाइल इस तरह दिखती है:

Line 1
Line 2
Line 3
Line 4
Line 5
Line 6

और n = 2, फिर आउटपुट होगा:

Line 3
Line 6

ऐसा लगता है कि sedऐसा करने में सक्षम हो सकता है, लेकिन मैं यह पता लगाने में सक्षम नहीं हूं कि कैसे। एक बैश कमांड आदर्श होगा, लेकिन मैं किसी भी समाधान के लिए खुला हूं।


2
क्या आप वास्तव में 1, 4, 7, इत्यादि के बजाय 1, 3, 6, आदि लाइन्स चाहते हैं?
इल्मरी करोनें

2
चूंकि यह एक CSV फ़ाइल है, इसलिए मुझे लगता है कि पहली पंक्ति में मेटा डेटा (यानी फ़ील्ड नाम) हैं। यदि हां, तो सवाल "पहले के बाद हर एनटी लाइन" होना चाहिए।
iglvzx

7
1, 3, 6 अभी भी समझ में नहीं आता है!
विम

1
मुझे लगता है कि यह 1, 3, 5 होना चाहिए जब तक n = 2 त्रिकोणीय संख्याओं (1, 3, 6, 10, 15, 21 आदि) के लिए एक जादुई मूल्य है
rjmunro

4
क्या आप अपने प्रश्न को अपडेट कर सकते हैं कि आप क्या कर रहे हैं ("हर nth लाइन", "n = 2") और अपने वांछित आउटपुट (लाइन 3, लाइन 6) के अनुरूप? भविष्य के पाठक भ्रमित होने वाले हैं।
कीथ थॉम्पसन

जवाबों:


121
~ $ awk 'NR == 1 || NR % 3 == 0' yourfile
Line 1
Line 3
Line 6

NR(रिकॉर्ड्स की संख्या) वेरिएबल रिकॉर्ड्स की संख्या है क्योंकि डिफ़ॉल्ट व्यवहार RS(रिकॉर्ड सेपरेटर) के लिए नई लाइन है । पैटर्न और कार्रवाई awk के डिफ़ॉल्ट प्रारूप में वैकल्पिक है 'pattern {actions}'। जब हम केवल पैटर्न भाग देते हैं तो हमारे पैटर्न की स्थितियों के लिए awkसभी फ़ील्ड लिखते हैं। $0true


8
चूक के लिए धन्यवाद, आपको इसकी भी आवश्यकता नहीं है:awk 'NR == 1 || NR % 3 == 0'
केविन

@selman: यदि आप केविन के समाधान को पसंद करते हैं, तो आप अपने उत्तर को अपडेट करने पर विचार कर सकते हैं।
कीथ थॉम्पसन

4
यह समझाने के लिए कि वह ऐसा क्यों करता है? इस तरह अगर कोई इसे थोड़ा
मोड़ना

मैंने पाया कि यह दृष्टिकोण मुझे 1 और 2 अछूता छोड़ देता है। इसकी पुष्टि awk 'NR == 1 || NR % 2 == 0' myfile.txt | wc -lएक विषम संख्या में हुई है, जबकि मूल फ़ाइल में समान संख्या में लाइनें थीं। मेरे परीक्षण के मामले में @kev उत्तर सबसे अच्छा काम करता है।
डैनियल दा कुन्हा

58

sed यह भी कर सकते हैं:

$ sed -n '1p;0~3p' input.txt
Line 1
Line 3
Line 6

man sedके ~रूप में बताते हैं :

पहला ~ चरण पहले चरण के साथ शुरू होने वाली प्रत्येक step'th लाइन से मेल खाता है। उदाहरण के लिए, `` sed -n 1 ~ 2p '' इनपुट स्ट्रीम में सभी विषम-संख्या वाली पंक्तियों को प्रिंट करेगा, और पता 2 ~ 5 हर पांचवें पंक्ति से मेल खाएगा, दूसरे से शुरू होगा। पहले शून्य हो सकता है; इस मामले में, sed संचालित होता है जैसे कि यह कदम के बराबर था। (यह एक विस्तार है।)


6
क्या आप इस आदेश की व्याख्या कर सकते हैं?
QED

1
@qed स्पष्टीकरण: 1pपहली लाइन को 0~3pप्रिंट करता है , लाइन 3 से शुरू होने वाली हर तीसरी लाइन 1pको प्रिंट करता है (इस प्रकार लाइन 1 को प्रिंट करना आवश्यक है)। लेकिन ध्यान दें कि 0~3मानक नहीं है, लेकिन एक GNU sed विस्तार है।
अर्कु

"यह एक विस्तार है।" आप कौन से संस्करण का उपयोग कर रहे हैं?
विक्टर

इस जवाब ने मुझे विंडोज़ पावरशेल के लिए बहुत मदद की। मैंने इसे इस तरह चौड़ा किया: sed -n '1p;0~10p' '.\in.txt' > out.txtकम की गई फाइल को आउटपुट-फाइल में प्रिंट करने के लिए।
किमलीव

22

पर्ल भी ऐसा कर सकते हैं:

while (<>) {
    print  if $. % 3 == 1;
}

यह प्रोग्राम इसके इनपुट की पहली लाइन और उसके बाद हर तीसरी लाइन को प्रिंट करेगा।

इसे थोड़ा समझाने के लिए, <>लाइन इनपुट ऑपरेटर है, जो whileइस तरह एक लूप में उपयोग किए जाने पर इनपुट लाइनों पर पुनरावृत्त करता है । विशेष चर $.में अब तक पढ़ी गई लाइनों की संख्या है, और %मापांक ऑपरेटर है।

यह कोड वन-लाइनर के रूप में और भी अधिक संक्षिप्त रूप से लिखा जा सकता है, -nऔर -eस्विच का उपयोग करते हुए :

perl -ne 'print if $. % 3 == 1'  < input.txt  > output.txt

-eस्विच, एक कमांड लाइन पैरामीटर के रूप में निष्पादित करने के लिए पर्ल कोड का एक टुकड़ा ले जाता है, जबकि -nस्विच परोक्ष एक में कोड लपेटता whileनीचे दिखाए गए जैसा पाश।


संपादित करें: वास्तव में लाइनों 1, 3, 6, 9, ... उदाहरण के रूप में, लाइनों 1, 4, 7, 10 के बजाय ... जैसा कि मैंने पहली बार माना था कि आप चाहते थे, के $. % 3 == 1साथ बदलें $. == 1 or $. % 3 == 0


7

यदि आप इसे बैश स्क्रिप्ट के साथ करना चाहते हैं तो आप कोशिश कर सकते हैं:

#!/bin/sh

echo Please enter the file name
read fname
echo Please enter the Nth lines that you want to keep
read n

exec<$fname
value=0
while read line
do
    if [ $(( $value % $n )) -eq 0 ] ; then
        echo -e "$line" >> new_file.txt
    fi
        let value=value+1 
done
echo "Check the 'new_file.txt' that has been created in this directory";

इसे "read_lines.sh" के रूप में सहेजें और बैश फ़ाइल को + x अनुमतियाँ देना याद रखें।

chmod +x ./read_lines.sh

1
यदि आपने इसे मानक मानक से बाहर कर दिया है, तो तर्कों को छोड़ने के लिए लाइनों की संख्या को पढ़ें और मानक से फ़ाइल को पढ़ें, यह सरल और अधिक उपयोगी होगा। आप अभी भी करके new_file.txt बना सकते हैं ./read_lines.sh > new_file.txt
rjmunro

4

शुद्ध बैश में एक समाधान, जो एक प्रक्रिया को स्पॉन नहीं करता है:

{ for f in {1..2}; do read line; done;
  while read line; do
    echo $line;
    for f in {1..2}; do read line; done;
  done; } < file

पहली पंक्ति फ़ाइल की शुरुआत में 2 लाइनों को छोड़ती है, और whileअगली पंक्ति को प्रिंट करती है और 2 लाइनों को फिर से छोड़ती है।

यदि आपकी फ़ाइल छोटी है, तो यह काम करने का एक बहुत ही कुशल तरीका है क्योंकि यह एक प्रक्रिया शुरू नहीं करता है। जब आपकी फ़ाइल बड़ी हो, sedतो इसका उपयोग किया जाना चाहिए क्योंकि यह io से निपटने में अधिक कुशल है bash


1

एक पायथन संस्करण (दोनों पायथन 2 एक पायथन 3):

python2 -c "print(''.join(open('file.txt').readlines()[::3]))"

[::3]अधिक नियंत्रण के लिए स्टार्ट, एंड और स्टेप साइज पैरामीटर से बदलें । जैसे [10:36:5]10,15, ..., 35 की पंक्तियाँ प्रस्तुत करता है।

ध्यान दें, जब readlines()से लाइन एंडिंग रहती है, इस कॉल का आउटपुट एक खाली अंतिम लाइन के साथ समाप्त हो सकता है, जब तक कि मूल अंतिम लाइन चुने हुए चरण के आकार से बाहर नहीं निकल जाती।

एक स्ट्रीम संस्करण भी संभव है, यहां (केवल उत्पादन समाप्त स्ट्रीम के बाद):

python -c "import sys;print(''.join(list(sys.stdin)[::3]))" < file.txt
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.