วิธีเก็บเฉพาะทุก ๆ บรรทัดของไฟล์


71

ฉันมีไฟล์ CSV ที่มีขนาดค่อนข้างใหญ่ (75MB) ฉันแค่พยายามสร้างกราฟของมันดังนั้นฉันจึงไม่ต้องการข้อมูลทั้งหมด

Rewording: ฉันต้องการลบ n บรรทัดจากนั้นเก็บหนึ่งบรรทัดจากนั้นลบ n บรรทัดและอื่น ๆ

ดังนั้นหากไฟล์มีลักษณะเช่นนี้:

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

และ n = 2 ดังนั้นผลลัพธ์จะเป็น:

Line 3
Line 6

ดูเหมือนว่าsedจะสามารถทำสิ่งนี้ได้ แต่ฉันไม่สามารถหาวิธีได้ คำสั่ง bash เหมาะอย่างยิ่ง แต่ฉันเปิดรับการแก้ไขใด ๆ


2
คุณต้องการบรรทัดที่ 1, 3, 6 และอื่น ๆ แทนที่จะเป็น 1, 4, 7 เป็นต้น
Ilmari Karonen

2
เนื่องจากเป็นไฟล์ CSV ฉันถือว่าบรรทัดแรกมีข้อมูลเมตา (เช่นชื่อฟิลด์) ถ้าเป็นเช่นนั้นคำถามควรเป็น "ทุก ๆ บรรทัดที่ n หลังจากบรรทัดแรก"
iglvzx

7
1, 3, 6 ยังไม่สมเหตุสมผล!
wim

1
ฉันเดาว่ามันควรจะเป็น 1, 3, 5 ยกเว้นว่า n = 2 เป็นค่าเวทย์มนตร์สำหรับตัวเลขสามเหลี่ยม (1, 3, 6, 10, 15, 21 ฯลฯ )
rjmunro

4
คุณสามารถอัปเดตคำถามของคุณเพื่อให้สิ่งที่คุณต้องการ ("ทุกบรรทัดที่ n", "n = 2") และผลลัพธ์ที่คุณต้องการ (บรรทัดที่ 3, บรรทัดที่ 6) สอดคล้องกันได้หรือไม่ ผู้อ่านในอนาคตจะสับสน
Keith Thompson

คำตอบ:


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

NR(จำนวนเรคคอร์ด) ตัวแปรคือบันทึกจำนวนบรรทัดเนื่องจากพฤติกรรมเริ่มต้นคือบรรทัดใหม่สำหรับRS(เรคคอร์ด seperator) 'pattern {actions}'รูปแบบและการกระทำที่จะเป็นตัวเลือกในรูปแบบเริ่มต้นของ awk เมื่อเราให้ส่วนรูปแบบเท่านั้นแล้วawkเขียนเขตข้อมูลทั้งหมด$0สำหรับtrueเงื่อนไขของรูปแบบของเรา


8
ด้วยค่าเริ่มต้นคุณไม่จำเป็นต้องมีอะไรมากมาย:awk 'NR == 1 || NR % 3 == 0'
Kevin

@selman: ถ้าคุณชอบวิธีการแก้ปัญหาของ Kevin คุณอาจต้องการพิจารณาปรับปรุงคำตอบของคุณ
Keith Thompson

4
สนใจที่จะอธิบายว่าทำไมมันถึงเป็นเช่นนั้น? ด้วยวิธีนี้หากมีคนต้องการปรับแต่งเล็กน้อยจากนั้นหวังว่าคำอธิบายของคุณจะช่วยให้พวกเขาทำเช่นนั้น
Ivo Flipse

ฉันพบว่าวิธีการนี้ปล่อยให้ฉันบรรทัดที่ 1 และ 2 แตะต้อง สิ่งนี้ได้รับการยืนยันพร้อมกับawk 'NR == 1 || NR % 2 == 0' myfile.txt | wc -lทำให้เกิดเลขคี่ในขณะที่ไฟล์ต้นฉบับมีจำนวนบรรทัดเท่ากัน @kev คำตอบทำงานได้ดีที่สุดในกรณีทดสอบของฉัน
Daniel Da Cunha

58

sed ยังสามารถทำสิ่งนี้:

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

man sedอธิบาย~ว่า:

~ ขั้นตอนแรกจับคู่ทุกบรรทัดบรรทัดที่เริ่มต้นด้วยบรรทัดแรก ตัวอย่างเช่น `` sed -n 1 ~ 2p '' จะพิมพ์บรรทัดเลขคี่ทั้งหมดในอินพุตสตรีมและที่อยู่ 2 ~ 5 จะจับคู่ทุกบรรทัดที่ห้าเริ่มต้นด้วยบรรทัดที่สอง แรกสามารถเป็นศูนย์ ในกรณีนี้ sed ทำงานราวกับว่ามันเท่ากับขั้นตอน (นี่คือส่วนขยาย)


6
คุณช่วยอธิบายคำสั่งนี้ได้ไหม
qed

1
@qed คำอธิบาย: 1pพิมพ์บรรทัดแรก0~3pพิมพ์ทุกบรรทัดที่สามโดยเริ่มจากบรรทัดที่ 3 ( 1pจำเป็นต้องพิมพ์บรรทัดที่ 1) แต่โปรดทราบว่า0~3มันไม่ได้มาตรฐาน แต่เป็นส่วนขยายของ GNU sed
Arkku

"นี่คือส่วนขยาย" คุณใช้เวอร์ชั่นไหน /
Victor

คำตอบนี้ช่วยฉันได้มากสำหรับ Windows PowerShell ฉันขยายมันแบบนั้นsed -n '1p;0~10p' '.\in.txt' > out.txtเพื่อพิมพ์ไฟล์ที่ลดขนาดลงในไฟล์เอาต์พุต
kimliv

22

Perlสามารถทำได้เช่นกัน:

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

โปรแกรมนี้จะพิมพ์บรรทัดแรกของอินพุตและทุกบรรทัดที่สามหลังจากนั้น

เพื่ออธิบายมันหน่อย<>เป็นตัวดำเนินการอินพุตบรรทัดซึ่งวนข้ามบรรทัดอินพุตเมื่อใช้ในwhileลูปแบบนี้ ตัวแปรพิเศษ$.มีจำนวนบรรทัดที่อ่านจนถึงตอนนี้และ%เป็นตัวดำเนินการโมดูลัส

รหัสนี้สามารถเขียนได้มากขึ้นอย่างกะทัดรัดเป็นหนึ่งซับโดยใช้-nและ-eสวิตช์:

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

-eสวิทช์ใช้เวลาชิ้นส่วนของรหัส Perl ที่จะดำเนินการเป็นพารามิเตอร์บรรทัดคำสั่งในขณะที่-nสวิทช์โดยปริยาย wraps รหัสในwhileวงอย่างหนึ่งที่แสดงไว้ข้างต้น


แก้ไข: จริงได้รับสาย 1, 3, 6, 9, ... เช่นในตัวอย่างมากกว่าสาย 1, 4, 7, 10, ... เป็นครั้งแรกที่ผมสันนิษฐานว่าคุณอยากเปลี่ยนด้วย$. % 3 == 1$. == 1 or $. % 3 == 0


7

หากคุณต้องการทำด้วยสคริปต์Bashคุณสามารถลอง:

#!/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 แก่ไฟล์ bash

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

รุ่น Python (ทั้ง Python 2 และ Python 3):

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

แทนที่[::3]ด้วยพารามิเตอร์เริ่มต้นสิ้นสุดและขนาดขั้นตอนสำหรับการควบคุมเพิ่มเติม Eg แสดง[10:36:5]บรรทัดที่ 10,15, ... , 35

หมายเหตุเนื่องจากreadlines()เก็บรักษาที่สิ้นสุดบรรทัดเอาท์พุทของการโทรนี้อาจจบลงด้วยบรรทัดสุดท้ายที่ว่างเปล่าเว้นเสียแต่ว่าบรรทัดสุดท้ายดั้งเดิมจะถูกเอาออกโดยขนาดขั้นตอนที่เลือก

เวอร์ชันของสตรีมก็เป็นไปได้เช่นกัน

python -c "import sys;print(''.join(list(sys.stdin)[::3]))" < file.txt
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.