จะตัดบางส่วนจากไฟล์บันทึกได้อย่างไร


18

ฉันมีไฟล์บันทึก 8 Gb (บันทึกการผลิตของ Rails) ฉันต้องตัดมันระหว่างวันที่ (เส้น) ฉันสามารถใช้คำสั่งใดในการทำสิ่งนี้


1
เฮ้พวกคำถามนี้เกี่ยวกับไฟล์ขนาดใหญ่ดังนั้นมันจึงเป็น "Ante up!" .. เวลาสำคัญ ... ฉันได้ทดสอบสคริปต์ sed ที่ชื่นชอบในไฟล์ขนาด 8 GB จริงด้วย 85904064 บรรทัด (100 ตัวอักษรต่อบรรทัด) ฉันชอบ sed แต่ตามที่ได้กล่าวไว้สคริปต์ sed จะสแกนไฟล์ทั้งหมดทุกครั้ง โดยเฉลี่ยแล้วช้ากว่าสคริปต์ awk ซึ่งออกเมื่อพบ ... ฉันคิดว่า (?) สคริปต์ sed อาจต้องการ aq แทนที่จะเป็น d สำหรับนิพจน์ที่สอง ... ผลการทดสอบอยู่ที่นี่: วาง .ubuntu.com / 573477 .. นอกจากนี้มันไม่ได้สร้างผลลัพธ์ที่เหมาะสม .. ดูความคิดเห็นของฉันที่ท้ายคำตอบของ asoundmove
Peter.O

รุ่น sed ใหม่ของ asoundmove ได้แก้ไขปัญหาความเร็วและตอนนี้ตรงกับความเร็วของ awks และรุ่นใหม่ในตอนนี้ส่งออกข้อมูลอย่างถูกต้อง ... ดูความคิดเห็นของเขาสำหรับรายละเอียดเพิ่มเติม
Peter.O

ฉันเพิ่งสังเกตว่าคุณพูดว่า "ตัด" (ซึ่งโดยทั่วไปหมายถึงการลบ) ... คุณหมายถึง "ตัด" หรือคุณหมายถึง "คัดลอก" หรือไม่? .... ถ้าคุณหมายถึง "บาดแผล" คุณsedจะทำได้อย่างง่ายดาย
Peter.O

คำตอบ:


12

สิ่งที่ต้องการ

sed '1,/last date prior to chunk/d;/first date after chunk/,$d' logfile | tee cut-log | less

tee cut-logcut-logช่วยให้คุณสามารถเห็นบนหน้าจอสิ่งที่จะถูกใส่ในแฟ้ม

แก้ไข:

เพื่อให้เป็นไปตามมาตรฐานที่เข้มงวดของ fred.bear ต่อไปนี้เป็นวิธีการแก้ปัญหาที่น่ากลัว (แม้ว่าเนื้อหาวิธีแก้ปัญหา awk จะสวยกว่ามาก):

b=BB; e=EE ;echo -e "AA\nAA\nBB\nBB\nCC\nCC\nDD\nDD\nEE\nEE\nFF\nFF" | sed -n ":b;/$b/b p;n;b b;:p;p;n;/$e/b e;b p;:e;p;n;/$e/b e;q"


3
@dogbane: ใช่ใช่ แก้ไข ฉันแน่ใจว่าบางครั้งคุณเขียนน้อยกว่ารหัสที่ดีที่สุดมันสมควรได้รับความคิดเห็นที่รุนแรงเช่นนี้หรือไม่?
asoundmove

1
หมายเหตุ: หากมีบรรทัด 'วันที่แรก' ติดต่อกันหลายรายการที่มีวันที่เหมือนกัน แต่ทั้งหมดจะไม่ถูกลบออกไปและจะถูกนำไปใช้กับเอาต์พุต ... สิ่งที่ต้องระวัง ... (ขึ้นอยู่กับ สถานการณ์)
Peter.O

1
... แต่ถึงแม้ว่าฉันจะเป็นมืออาชีพ ++ ฉันคิดว่างานนี้มันเกินขีด จำกัด สำหรับสิ่งอื่นใดนอกจากเครื่องมือส่วนตัวของตัวเอง .. นี่คือปัญหาหลักที่มีอยู่ในกรณีนี้ (ของคุณและ ฉัน .. ฉันจัดการที่จะทำเช่นเดียวกับคุณ .. มันก็วิ่งภายใน 1%) .. กลับไปที่ปัญหาหลัก .. (ซึ่งไม่ได้ใช้กับ awk) .... ข้อผิดพลาด (ไม่สามารถแก้ไขได้): เกี่ยวกับวันที่ที่ถูกต้องภายในขอบเขตของบันทึก แต่ไม่ได้มีอยู่จริงในบันทึกจะในกรณีของ ARG 1 ทำให้เกิดความไม่พอใจที่จะพิมพ์อะไรและในกรณีของ ARG ที่ 2 พิมพ์ทุกอย่าง หลังจากวันแรก! ... เพิ่มเติม ...
Peter.O

1
อีกข้อผิดพลาดที่แก้ไขได้: มันตรงกับวันที่ใด ๆ ในบรรทัดรวมถึงการประท้วงข้อมูล แต่นั่นเป็นเพียงแค่บิด regex .. และสำหรับใครก็ตามที่ต้องการใช้บางทีคุณอาจแสดงความคิดเห็นว่า args ตอนนี้อ้างถึงครั้งแรกและ วันที่ล่าสุดอยู่ในช่วง (ไม่ใช่ -1 และ +1) .. และสุดท้าย .. "มาตรฐานที่เข้มงวด" ของฉันไม่ใช่ของฉัน ฉันเป็นเพียงผู้ส่งสารของผู้ถามคำถาม ... ผู้ใช้จะสังเกตเห็นว่ามันใช้งานได้ตามที่ร้องขอหรือไม่ .. นี่เป็นคำถามที่ยอดเยี่ยมสำหรับฉัน .. ฉันเรียนรู้มามากมาย :) ... และฉันดีใจ เพื่อทราบว่าsedสามารถจับคู่กับawkความเร็วได้และเร็วขึ้นเล็กน้อย
Peter.O

6

หากต้องการพิมพ์ทุกอย่างระหว่าง FOO และ BAR ให้ลอง:

$ sed -n '/FOO/,/BAR/p' file.txt

1
หมายเหตุ: นี่จะพิมพ์บาร์ชุดแรกของชุดบาร์ติดต่อกันเท่านั้น ...
Peter.O

หมายเหตุอื่น ... ปัญหาใหญ่ถ้าวันใดวันหนึ่งไม่ปรากฏในข้อมูล .. หากวันสุดท้ายไม่ปรากฏ sed จะเก็บบรรทัดเอาท์พุทจนกว่าจะถึง EOF
Peter.O

5

สิ่งนี้จะทำสิ่งที่คุณต้องการ ...
ทั้งการรวมและไม่รวมวันที่พารามิเตอร์จะแสดงขึ้น

# set Test args
set  2011-02-24  2011-02-26  "junk"

from="$1"
till="$2"
file="$3"

# EITHER ====                              +++++++++  
# Ouptut lines between two parameter dates INCLUDING the parameter dates
  awk -v from=$from -v till=$till '
    ($2 >= from) && ($2 <= till) { print $0 ; next }
    ($2 > till) { exit }' "$file"

# OR ========                              ---------
# Ouptut lines between two parameter dates EXCLUDING the parameter dates
  awk -v from=$from -v till=$till '
    ($2 > from) && ($2 < till) { print $0 ; next }
    ($2 >= till) { exit }' "$file"

มันทดสอบสำหรับวันที่ (เรียงลำดับ) ในฟิลด์ 2 ... นี่คือตัวอย่างสำหรับข้อมูลการทดสอบ

    98  2011-02-05 xxxx
    99  2011-02-05 xxxx
   100  2011-02-06 xxxx
   101  2011-02-06 xxxx

และนี่ก็เป็นเครื่องกำเนิดไฟฟ้าทดสอบข้อมูล


ฉันจะเขียน (ยกตัวอย่างคนแรก) เพียงเล็กน้อยดังนั้น: awk -v from="$from" -v till="$till" '($2 >= from) { if ($2 <= till) { print } else { exit }' "$file"
asoundmove

@asoundmove: ใช่มันอาจจะดูดีกว่าและมันก็ธรรมดากว่า แต่ในความเป็นจริงเวลาในการดำเนินการของมันเป็นเพียงช่วงเวลาของการเพิ่ม 1 ifคำสั่งทั้งหมด (ไม่แม้แต่ 1 ต่อบรรทัด) เช่น ตรรกะไหลเหมือนกันอย่างมีประสิทธิภาพและความแตกต่างในเวลาทำงานจะถูกนับเป็น nanoseconds .... เหตุผลเดียวที่ฉันไม่ได้ใช้ "อื่น" คือว่านี่เป็นawkสคริปต์แรกของฉันที่มีประสิทธิภาพ(นอกเหนือจากหนึ่งวัน 4 ปี ที่ผ่านมาเมื่อฉันเล่นกับตัวอย่าง) ... และนั่นคือกลไกสาขาที่สามารถทำงานได้ครั้งแรกที่ฉันพบ ... (และตามที่กล่าวไว้มันเป็นไปอย่างรวดเร็ว) .. ฉันมักจะใช้sedลองq
Peter.O

ฉันไม่เข้าใจที่คุณให้ชื่อไฟล์ข้อความและที่ตั้งในวิธีนี้? ใครบางคนสามารถช่วยให้ฉันเห็นผ่านความโง่เขลาของฉัน
ไจล์ส

4

หากในไฟล์บันทึกของคุณคุณมีวันที่ในรูปแบบนี้YYYY-MM-DDดังนั้นเมื่อต้องการค้นหารายการทั้งหมดสำหรับพูด 2011-02-10 คุณสามารถทำได้:

grep 2011-02-10 log_file

ตอนนี้ถ้าคุณต้องการค้นหารายการสำหรับ 2011-02-10 และ 2011-02-11 ให้ใช้อีกครั้งgrepแต่มีหลายรูปแบบ:

grep -E '2011-02-10|2011-02-11' log_file

ดี. ใช้งานได้ "ตามที่โฆษณา" :) ... อย่างไรก็ตามgrepจะค้นหาไฟล์ทั้งหมดแม้ว่าช่วงวันที่จะเป็นจุดเริ่มต้นของไฟล์ โดยเฉลี่ยนี้จะเพิ่มเวลาการค้นหาเป็นสองเท่าเมื่อเปรียบเทียบกับ "exit-after-last-item-in-range" ... ฉันแค่อยากจะพูดถึงสิ่งนี้เพราะขนาดไฟล์ 8 GB ที่กล่าวถึงในคำถามของคุณ ผลลัพธ์เวลา grep เกือบเหมือนตัวอย่าง sed ที่นี่ (1 นาที 58 วินาที) นี่คือลิงค์ไปยังผลการทดสอบเวลาของฉัน: paste.ubuntu.com/573477
Peter.O

1

การทำงานกับไฟล์ขนาดนี้เป็นเรื่องยากเสมอ

วิธีข้างหน้าอาจแบ่งไฟล์นี้ออกเป็นไฟล์เล็ก ๆ สองสามไฟล์เพื่อทำสิ่งนี้คุณสามารถใช้คำสั่ง split

split -d -l 50000 ToBigFile.data file_

แม้เจ้ามันจะถูกแยกออกคุณยังสามารถทำงานกับไฟล์ได้เหมือนจะเป็นไฟล์ที่ใช้ bash for loop

for f in `ls file_*`; do cat $f; done;

แต่แทนที่จะเป็นแมวคุณสามารถใช้ grep คว่ำเพื่อกำจัดข้อมูลที่ไม่ต้องการซึ่งไม่เกี่ยวข้องสำหรับสิ่งนี้ (หรือประเภทของการปรับแต่งที่คุณต้องการ)

ณ จุดนี้คุณจะทำงานกับไฟล์ขนาดเล็กจำนวนมากและคำสั่งอื่น ๆ ที่กล่าวถึงข้างต้นจะทำงานในไฟล์ขนาดเล็กจำนวนมาก

และเมื่อคุณทำเสร็จแล้วคุณสามารถใช้ครั้งที่สองสำหรับการวนซ้ำเพื่อสร้างไฟล์ขนาดเล็กลงใหม่อีกครั้ง

for f in `ls file_*`; do cat $f >> NewFile.data ; done;

อัปเดต เนื่องจากเราเริ่มแบ่งข้อมูลออกเป็นหลายไฟล์จึงมีงานจำนวนมากกับฮาร์ดไดรฟ์และต้องใช้เวลา (ในคำถามนี้เห็นได้ชัดว่า 5 นาที)

ในอีกทางหนึ่งขั้นตอนต่อไปอาจจะเร็วกว่า

ดังนั้นวิธีนี้อาจไม่มีจุดหมายสำหรับการดำเนินการ grep, awk, sed แบบง่าย ๆ แต่ถ้ารูปแบบการค้นหาซับซ้อนมากขึ้นมันอาจกลายเป็นเร็วขึ้น


3
Johanm ใช้เวลา awk และ sed เพียง 1 นาทีโดยเฉลี่ยเพื่อค้นหาล็อกไฟล์ 8 GB บนคอมพิวเตอร์ของฉันและ compuer เดียวกันเพียงแค่แบ่งไฟล์ inital ใช้เวลา 4 นาที 43 วินาที ... :)
Peter.O

สมมติว่าคุณสามารถลดเวลา awk และ sed เหล่านั้นลง 50% สำหรับไฟล์ขนาดเล็กลง จากนั้นเรายังคงต้องดำเนินการมากกว่า 10 ครั้งก่อนที่เราจะได้รับในเวลาทั้งหมด ... ดังนั้นบางทีการแบ่งไฟล์อาจไม่ใช่ความคิดที่ดีที่สุดสำหรับการถดถอยสองสามครั้ง ...
Johan

สคริปต์ awk สามารถ (ได้อย่างง่ายดาย) สามารถปรับเปลี่ยนเป็นผลลัพธ์การค้นหา 10 แบบแตกต่างกันเป็น 10 ไฟล์ .. ในการส่งผ่านครั้งเดียว แต่นั่นจะทำให้การอ่านช้าลงในขณะที่การส่งออกรายงานจริง ... Sed ยังสามารถทำเช่นเดียวกัน มีการกล่าวถึงในความคิดเห็นของ asoundmove, sed จะล้มเหลวหากวันที่ / เวลาที่ระบุไม่มีรายการในบันทึก (เช่นคุณกำลังค้นหาตามชั่วโมง) .. ฉันใช้ sed มากและมีประโยชน์มาก แต่ก็มีข้อ จำกัด ... นี่คือคำถามที่พบบ่อยเกี่ยวกับการใช้ sed vs awk .. ฉันไม่จำเป็นต้องเห็นด้วยทั้งหมด แต่ฉันสามารถเห็นความหมาย ... sed.sourceforge.net/sedfaq6.html
Peter O

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