วิธีที่ดีที่สุดในการแยกเซกเมนต์ออกจากไฟล์ข้อความคืออะไร


13

เป็นวิธีที่ดีในการแยกคำพูดคืออะไรบรรทัดที่ 20 -45 จากไฟล์ข้อความขนาดใหญ่ แน่นอนว่าไม่ใช่แบบโต้ตอบ!

คำตอบ:


12

คุณสามารถลอง:

cat textfile | head -n 45 | tail -n 26

หรือ

cat textfile | awk "20 <= NR && NR <= 45" 

อัปเดต:

ในฐานะที่เป็น Mahomedalid ชี้ให้เห็นว่าcatไม่จำเป็นและค่อนข้างซ้ำซ้อน แต่มันทำให้คำสั่งที่สะอาดและสามารถอ่านได้

ถ้าcatรบกวนคุณการแก้ปัญหาที่ดีกว่าก็คือ:

<textfile awk "20 <= NR && NR <= 45"

2
awk NR==20,NR==45 textfileทำงานเกินไปและอ่านได้อย่างง่ายดาย
ephemient

ฉันชอบการใช้ stdin มากกว่านี้มีความสอดคล้องระดับโลกกับส่วนที่เหลือของ nix
Stefan

1
การอ่านจากอาร์กิวเมนต์บรรทัดคำสั่งมีความสอดคล้องกับยูทิลิตี UNIX อื่น ๆ ด้วยและประเด็นหลักของฉันคือแสดงให้เห็นถึง,โอเปอเรเตอร์ช่วงของ awk
ephemient

ฮ่า ๆ ฉันหมายถึง @adam แต่ใช่ฉันชอบคำแนะนำของคุณ
Stefan

ฉันคิดว่าคำตอบของ @ ephemient เป็นคำตอบที่ดีที่สุดที่นี่ มิฉะนั้นคำสั่งจะค่อนข้างลึกลับ
LéoLéopold Hertz

13

ง่ายยิ่งขึ้น:

sed -n '20,45p;45q' < textfile

แฟล็ก -n ปิดใช้งานเอาต์พุตดีฟอลต์ ที่อยู่ "20,45" ประกอบด้วย 20 ถึง 45 บรรทัด คำสั่ง "p" พิมพ์บรรทัดปัจจุบัน และ q หยุดทำงานหลังจากพิมพ์บรรทัด


1
+1 ดีผมชอบ แต่สาย 20-45 :)
สเตฟาน

1
ตกลงตกลงฉันแก้ไขให้พูด 20,45 :-)
dkagedal

การลบqคำสั่ง (ทุกอย่างเริ่มต้นจาก;) ปรับปรุงประสิทธิภาพให้ฉันเมื่อทำการแยกบรรทัดเดียว 26995107 ออกจากไฟล์ 27169334 บรรทัด
Ruslan

6

นี่ไม่ใช่คำตอบ แต่ไม่สามารถโพสต์เป็นความคิดเห็นได้

อีกวิธีที่รวดเร็ว (มาก) ที่mikeserv แนะนำคือทำที่นี่ :

{ head -n 19 >/dev/null; head -n 26; } <infile

ใช้ไฟล์ทดสอบเดียวกันกับที่นี่และขั้นตอนเดียวกันนี่คือมาตรฐานบางอย่าง (แยกบรรทัด 1000020-1000045):

mikeserv :

{ head -n 1000019 >/dev/null; head -n 26; } <iplist

real    0m0.059s

สเตฟาน :

head iplist -n 1000045 | tail -n 26

real    0m0.054s

นี่เป็นวิธีแก้ปัญหาที่เร็วที่สุดและความแตกต่างนั้นเล็กน้อย(สำหรับรอบเดียว) (ฉันลองด้วยช่วงที่ต่างกัน: สองบรรทัด, ล้านเส้น ฯลฯ )

การทำโดยไม่ใช้ท่ออาจมีข้อได้เปรียบที่สำคัญอย่างไรก็ตามสำหรับแอปพลิเคชันที่ต้องการค้นหาช่วงของบรรทัดที่หลากหลายในลักษณะที่คล้ายกันเช่น:

for  pass in 0 1 2 3 4 5 6 7 8 9
do   printf "pass#$pass:\t"
     head -n99 >&3; head -n1
done <<1000LINES 3>/dev/null
$(seq 1000)
1000LINES

... ที่พิมพ์ ...

pass#0: 100
pass#1: 200
pass#2: 300
pass#3: 400
pass#4: 500
pass#5: 600
pass#6: 700
pass#7: 800
pass#8: 900
pass#9: 1000

... และอ่านไฟล์ผ่านครั้งเดียวเท่านั้น


โซลูชันอื่น ๆsed/ awk/ perlอ่านไฟล์ทั้งหมดและเนื่องจากไฟล์นี้เป็นไฟล์ขนาดใหญ่จึงไม่มีประสิทธิภาพ ฉันโยนในตัวเลือกบางอย่างที่exitหรือquit หลังจากบรรทัดสุดท้ายในช่วงที่ระบุ:

สเตฟาน :

awk "1000020 <= NR && NR <= 1000045" iplist

real    0m2.448s

เมื่อเทียบกับ

awk "NR >= 1000020;NR==1000045{exit}" iplist

real    0m0.243s

dkagedal ( sed):

sed -n 1000020,1000045p iplist

real    0m0.947s

เมื่อเทียบกับ

sed '1,1000019d;1000045q' iplist

real    0m0.143s

สตีเวน D :

perl -ne 'print if 1000020..1000045' iplist

real    0m2.041s

เมื่อเทียบกับ

perl -ne 'print if $. >= 1000020; exit if $. >= 1000045;' iplist

real    0m0.369s

+1 ฉันคิดว่านี่เป็นคำตอบที่ดีที่สุดที่นี่! มันจะเป็นการดีถ้าคุณใช้เวลากับมันawk NR==1000020,NR==1000045 textfileในระบบของคุณ
LéoLéopold Hertz

3
ruby -ne 'print if 20 .. 45' file

1
เพื่อน rubyist คุณจะได้รับคะแนนโหวตของฉัน
Stefan

1
ในขณะที่เราอยู่ที่นี่ทำไมไม่python -c 'import fileinput, sys; [sys.stdout.write(line) for nr, line in enumerate(fileinput.input()) if 19 <= nr <= 44]'เช่นกัน :-P นี่คือสิ่งที่ Ruby ซึ่งจำลองตาม Perl ซึ่งได้แรงบันดาลใจจาก awk / sed สามารถทำได้อย่างง่ายดาย
ephemient

2

เนื่องจาก sed และ awk ได้ถูกดำเนินการไปแล้วนี่เป็นวิธีแก้ไขปัญหา:

perl -nle "print if ($. > 19 && $. < 46)" < textfile

หรือตามที่ระบุไว้ในความคิดเห็น:

perl -ne 'print if 20..45' textfile

2
ตัวละครพิเศษเหล่านั้นคืออะไร? ไม่จำเป็นต้องตัดและเพิ่มการขึ้นบรรทัดใหม่ flip-flop จะถือว่าเป็นการเปรียบเทียบกับหมายเลขบรรทัดและตัวดำเนินการเพชรจะทำงานผ่านอาร์กิวเมนต์หากมีการจัดเตรียมไว้ perl -ne'print if 20..45' textfile
ephemient

1
ดี - นิด ๆ หน่อย ๆ ฉันคิดว่าสำหรับส่วนที่เหลือฉันไม่มีข้อแก้ตัวใด ๆ ที่จะช่วยให้เขาไม่รู้
Steven D
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.