วิธีรับข้อความจากช่วงวันที่โดยใช้ grep / sed ในไฟล์ข้อความขนาดใหญ่


9

ฉันมีข้อความไฟล์ใหญ่ (เกือบ 3GB) - มันเป็นไฟล์บันทึก ฉันต้องการรับบรรทัดข้อความที่ตรงกับช่วงวันที่จากไฟล์นี้ตั้งแต่วันที่ 13 กรกฎาคมถึง 19 กรกฎาคม รูปแบบบันทึกของฉันคือ:

2016-07-12 < ?xml version>
2016-07-13 < ?xml version>
2016-07-18 < ?xml version>
2016-07-18 < ?xml version>
2016-07-19 < ?xml version>
2016-07-20 < ?xml version>
sample text sample text
sample text sample text
sample text sample text
2016-07-20 < ?xml version>
sample text sample text
2016-07-20 < ?xml version>

ดังนั้นหลังจากgrep/ sedมันควรจะเป็นผลลัพธ์เช่นนี้

2016-07-13 < ?xml version>
2016-07-18 < ?xml version>
2016-07-18 < ?xml version>
2016-07-19 < ?xml version>

ฉันจะได้รับสิ่งนี้ได้อย่างไร


2
คุณแน่ใจว่าคุณหมายถึงมิถุนายน ? วันที่ทั้งหมดในไฟล์บันทึกตัวอย่างของคุณอยู่ในเดือนกรกฎาคมและตัวอย่างผลลัพธ์ที่ต้องการหมายถึงคุณหมายถึงหลัง
David Foerster

คำตอบ:


13

ด้วยgrepถ้าคุณทราบจำนวนบรรทัดที่คุณต้องการคุณสามารถใช้ตัวเลือกบริบท-Aเพื่อพิมพ์บรรทัดหลังจากรูปแบบ

grep -A 3 2016-07-13 file

ที่จะทำให้คุณสอดคล้องกับ 2013-07-13 และ 3 บรรทัดถัดไป

ด้วยsedคุณสามารถใช้วันที่เพื่อกำหนดขอบเขตเช่นนี้

sed -n '/2016-07-13/,/2016-07-19/p' file

ซึ่งจะพิมพ์ทุกบรรทัดจากบรรทัดแรกด้วย 2016-07-13 และรวมถึงบรรทัดแรกด้วย 2016-07-19 แต่ถือว่าคุณมีเพียงบรรทัดเดียวกับ 2016-07-19 (มันจะไม่พิมพ์บรรทัดถัดไป) หากมีหลายบรรทัดให้ใช้วันที่ถัดไปแทนและใช้dเพื่อลบเอาต์พุตจากมัน

sed -n '/2016-07-13/,/2016-07-20/{/2016-07-20/d; p}' file

11

ซับหนึ่ง grep ที่เรียบง่ายนี้จะเพียงพอ:

grep -E ^2016-07-1[3-9] filename

ทำงานได้ดีที่นี่และไม่จำเป็นต้อง sed :)

อ้างอิง:


1
คุณนำความสง่างามเช่นเคย :)
Zanna

(y) ... ต้องลบ^เพื่อให้ทำงานได้ ใช้งาน Mac
Anum Sheraz

4

awk สารละลาย:

$ awk '/^2016-07-13.*/,/2016-07-19.*/'  input.txt                                   
2016-07-13 < ?xml version> 
2016-07-18 < ?xml version> 
2016-07-18 < ?xml version> 
2016-07-19 < ?xml version> 

โดยทั่วไปพิมพ์บรรทัดใด ๆ จากบรรทัดที่ขึ้นต้นด้วยบรรทัด2016-07-13ที่เริ่มต้นด้วย2016-07-19


4

คำตอบปัจจุบันทั้งหมดขึ้นอยู่กับความจริงที่ว่ารายการไฟล์บันทึกถูกเรียงลำดับตามลำดับเวลาหรือความจริงที่ว่าช่วงวันที่สามารถจับคู่ได้อย่างง่ายดายด้วยนิพจน์ทั่วไป หากคุณต้องการวิธีแก้ปัญหาทั่วไปเพิ่มเติมเราจำเป็นต้องทำการเขียนโปรแกรมเพิ่มเติม

ฉันนำเสนอสคริปต์ GNU AWK นี้:

#!/usr/bin/gawk -f
BEGIN {
    starttime = mktime(starttime)
    endtime = mktime(endtime)
}

func in_range(n, start, end) {
    return start <= n && n < end
}

match($0, /^([0-9]{4})-([0-9]{2})-([0-9]{2})\s/, m) &&
    in_range(mktime(m[1] " " m[2] " " m[3] " 00 00 00"), starttime, endtime)

คุณให้เวลาเริ่มต้นและสิ้นสุดผ่านตัวแปรstarttimeและendtimeในรูปแบบที่mktimeเข้าใจ ( YYYY MM DD hh dd ss) ดังนั้นคุณจึงเรียกใช้awkคำสั่งเช่นนั้นโดยสมมติว่าสคริปต์ Awk ด้านบนอยู่ในไฟล์ปฏิบัติการfilter-log-dates.awkในไดเรกทอรีการทำงานปัจจุบันและไฟล์บันทึกคือmylog.txt:

./filter-log-dates.awk -v starttime='2016 07 13 00 00 00' -v endtime='2016 07 20 00 00 00' mylog.txt

โปรดทราบว่าเวลาสิ้นสุดเป็นแบบพิเศษนั่นคือบันทึกบันทึกที่ถูกต้องจะต้องมีการประทับเวลาก่อนเวลาสิ้นสุด

หากรูปแบบการประทับเวลาของคุณแตกต่างกันคุณสามารถปรับการแสดงออกปกติที่ส่งผ่านไปยังmatchฟังก์ชันให้เหมาะสม


3

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

grep -n 2016-07-13 bigtextfile | head -1
grep -n 2016-07-19 bigtestfile | tail -1
# Say the first number is 1234 and the second 5678, then use...
awk 'NR>=1234 && NR<=5678' bigtestfile > rangeoftext

สิ่งนี้สามารถทำได้ทั้งหมดในawkคำสั่ง แต่ขั้นตอนอาจทำให้ง่ายต่อการติดตาม ภายใน awk ตัวแปร NR คือหมายเลขบรรทัดปัจจุบันและเนื่องจากไม่ได้ระบุการดำเนินการหลังจากรูปแบบ (NR> = 1234 && NR <= 5678) การกระทำเริ่มต้นคือการพิมพ์บรรทัดที่อยู่ในช่วงนั้น

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