Bagaimana cara mendapatkan teks dari rentang tanggal menggunakan grep / sed dalam file teks besar?

9

Saya memiliki teks file besar (hampir 3GB) - ini adalah file log. Saya ingin mendapatkan baris teks yang sesuai dengan rentang tanggal dari file ini, dari 13 Juli hingga 19 Juli. Format log saya adalah:

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>

jadi setelah grep/ sedseharusnya output seperti ini:

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

Bagaimana saya bisa mendapatkan ini?

corey
sumber
2
Apakah Anda yakin maksud Anda Juni ? Semua tanggal dalam file log sampel Anda pada bulan Juli dan sampel output yang diinginkan menyiratkan yang Anda maksud adalah yang terakhir.
David Foerster

Jawaban:

13

Dengan grepjika Anda tahu jumlah garis yang Anda inginkan, Anda dapat menggunakan opsi konteks -Auntuk mencetak garis setelah pola

grep -A 3 2016-07-13 file

itu akan memberi Anda garis dengan 2013-07-13 dan 3 baris berikutnya

dengan sedAnda dapat menggunakan tanggal untuk membatasi seperti ini

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

yang akan mencetak semua baris dari baris pertama dengan 2016-07-13 hingga dan termasuk baris pertama dengan 2016-07-19. Tapi itu mengasumsikan Anda hanya memiliki satu baris dengan 2016-07-19 (tidak akan mencetak baris berikutnya). Jika ada beberapa baris gunakan tanggal berikutnya dan gunakan duntuk menghapus output dari itu

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

Grep one liner sederhana ini sudah cukup:

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

Bekerja dengan baik di sini dan tidak perlu sed :)

Referensi:

andrew.46
sumber
1
Seperti biasa Anda membawa rahmat :)
Zanna
(y) ... harus menghapus ^untuk membuatnya berfungsi. Menggunakan Mac.
Anum Sheraz
4

awk larutan:

$ 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> 

Pada dasarnya mencetak setiap baris dari yang dimulai dengan 2016-07-13yang dimulai dengan2016-07-19

Sergiy Kolodyazhnyy
sumber
4

Semua jawaban saat ini bergantung pada fakta bahwa entri file log diurutkan secara kronologis atau fakta bahwa rentang tanggal dapat dicocokkan dengan mudah dengan ekspresi reguler. Jika Anda menginginkan solusi yang lebih umum, kita perlu melakukan beberapa pemrograman lagi.

Saya menyajikan skrip GNU AWK ini:

#!/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)

Anda memberikan waktu mulai dan berakhir melalui variabel starttimedan endtimedalam format yang mktimememahami ( YYYY MM DD hh dd ss). Dengan demikian Anda menjalankan awkperintah seperti itu, dengan asumsi bahwa skrip Awk di atas adalah dalam file yang dapat dieksekusi filter-log-dates.awkdi direktori kerja saat ini dan file log adalah mylog.txt:

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

Perhatikan bahwa waktu akhir bersifat eksklusif , yaitu catatan log yang valid harus memiliki stempel waktu sebelum waktu berakhir.

Jika format cap waktu Anda berbeda, Anda dapat menyesuaikan ekspresi reguler yang dilewatkan ke matchfungsi yang sesuai dengannya.

David Foerster
sumber
3

Anda bisa melakukannya dalam langkah-langkah. Temukan jumlah baris pertama yang cocok dengan pola awal Anda. Temukan jumlah baris terakhir yang cocok dengan pola akhir Anda. Kemudian ekstrak tes di antara dua baris ini. Hal ini dapat dilakukan sebagai berikut.

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

Ini bisa dilakukan semua dalam sebuah awkperintah tetapi langkah-langkahnya mungkin membuatnya lebih mudah untuk diikuti. Dalam awk, variabel NR adalah nomor baris saat ini, dan karena tidak ada tindakan yang ditentukan setelah pola (NR> = 1234 && NR <= 5678) tindakan default adalah mencetak garis-garis yang berada dalam kisaran itu.

Jeffrey Ross
sumber