Bagaimana cara memotong bagian dari file log?

18

Saya memiliki file log 8 Gb (log produksi Rails). Saya perlu memotongnya di antara beberapa tanggal (garis). Perintah mana yang bisa saya gunakan untuk melakukan ini?

Eric Leschinski
sumber
1
Hai teman-teman, pertanyaan ini adalah tentang file besar , jadi "Ante up!" .. masalah waktu ... Saya sudah menguji skrip sed favorit pada file 8 GB nyata, dengan 85904064 baris (100 karakter per baris). Saya suka sed, tapi seperti biasa, skrip sed memindai seluruh file, setiap saat. Ini membuatnya rata-rata dua kali lebih lambat dari skrip awk yang keluar-ketika-ditemukan ... Saya pikir (?) Skrip sed mungkin hanya perlu aq daripada d untuk ekspresi kedua ... Hasil tes di sini: tempel .ubuntu.com / 573477 .. Juga, itu tidak menghasilkan output yang tepat .. lihat komentar saya di akhir jawaban asoundmove.
Peter.O
Versi sed baru asoundmove telah membahas masalah kecepatan, dan sekarang cocok dengan kecepatan awks. dan versin baru sekarang menampilkan data dengan benar ... lihat komentarnya untuk lebih detail.
Peter.O
Saya baru saja memperhatikan Anda mengatakan "memotong" (yang biasanya berarti menghapus) ... Apakah Anda benar-benar bermaksud "memotong", atau maksud Anda "menyalin"? .... Jika Anda memang bermaksud "memotong", maka sedakan melakukannya dengan mudah.
Peter.O

Jawaban:

12

Sesuatu seperti

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

tee cut-logmemungkinkan Anda melihat di layar apa yang dimasukkan ke dalam file cut-log.

EDIT:

Untuk memenuhi standar menuntut fred.bear, inilah solusi sed (meskipun solusi awk bisa dibilang jauh lebih cantik):

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"
pindahkan
sumber
3
@dogbane: yeah, yeah. Diedit. Saya yakin Anda kadang-kadang menulis kode yang kurang optimal, apakah pantas mendapatkan komentar yang keras?
asoundmove
1
Catatan: Jika ada beberapa baris 'kencan pertama' berturut-turut dengan tanggal yang sama, semua kecuali yang pertama tidak akan dihapus, dan akan diperkenalkan ke output ... hanya sesuatu yang harus diperhatikan ... (tergantung pada situasinya)
Peter.O
1
... tapi, meskipun saya seorang pro-sed ++, saya pikir pekerjaan khusus ini di luar batasnya, untuk apa pun selain alat pribadi seseorang .. Berikut adalah masalah utama yang dimiliki oleh dalam kasus ini (milik Anda, dan saya .. Saya berhasil mendapatkan sed untuk melakukan hal yang sama seperti milik Anda .. itu juga berjalan dalam 1%) .. kembali ke masalah utama .. (yang tidak berlaku untuk awk) .... Bug (tidak dapat diperbaiki): Mengenai tanggal yang valid dalam lingkup log, tetapi tidak benar-benar hadir dalam log akan, dalam kasus arg 1, menyebabkan sed untuk tidak mencetak apa-apa, dan dalam kasus arg 2, sed akan mencetak semuanya setelah kencan pertama! ... lebih lanjut ...
Peter.O
1
Bug lain yang dapat diperbaiki: Apakah saat ini cocok dengan tanggal di mana saja di baris mana pun, termasuk data sementara, tapi itu hanya perubahan regex .. Dan bagi siapa pun yang ingin menggunakannya, mungkin Anda bisa berkomentar bahwa argumen sekarang merujuk pada yang pertama dan tanggal terakhir dalam kisaran (bukan -1 dan +1) .. dan akhirnya .. "standar rewel" saya bukan milik saya. Saya hanya utusan permintaan Penanya ... Pengguna akan melihat apakah itu berfungsi seperti yang diminta, atau tidak .. Ini telah menjadi pertanyaan besar bagi saya .. Saya telah belajar banyak :) ... dan saya senang untuk mengetahui bahwa sedbisa cocok awkuntuk kecepatan, dan itu sebenarnya sedikit lebih cepat.
Peter.O
6

Untuk mencetak semuanya antara FOO dan BAR termasuk, coba:

$ sed -n '/FOO/,/BAR/p' file.txt
dogbane
sumber
1
catatan: Ini hanya akan mencetak BAR pertama dari serangkaian BAR berturut-turut ...
Peter.O
catatan lain ... Masalah besar jika salah satu tanggal tidak ada dalam data .. Jika tanggal terakhir tidak ada, sed akan tetap mengeluarkan garis hingga mencapai EOF.
Peter.O
5

Ini akan melakukan apa yang Anda inginkan ...
Termasuk dan tidak termasuk tanggal parameter ditampilkan.

# 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"

Ini menguji untuk tanggal (diurutkan) di bidang 2 ... Berikut ini adalah contoh untuk data pengujian

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

Dan di sini adalah generator uji-data .

Peter.O
sumber
Saya akan menulisnya (mengambil contoh pertama) sedikit lebih sederhana sebagai berikut: awk -v from="$from" -v till="$till" '($2 >= from) { if ($2 <= till) { print } else { exit }' "$file"
asoundmove
@asoundmove: Ya, itu mungkin terlihat lebih baik, dan itu pasti lebih konvensional , tetapi pada kenyataannya, waktu pelaksanaannya hanya durasi 1 ifpernyataan tambahan secara total (bahkan 1 per baris) yaitu. alur logikanya sama, dan perbedaan dalam run time akan dihitung dalam nanodetik .... Satu-satunya alasan saya tidak menggunakan "lain" adalah karena ini secara efektif merupakan awkskrip pertama saya (selain dari satu hari 4 tahun) lalu ketika saya bermain dengan beberapa contoh) ... dan itu adalah mekanisme cabang yang bisa diterapkan pertama yang saya temukan ... (dan seperti yang disebutkan. Ini sama cepatnya) .. Saya secara umum menggunakan sedTryq
Peter.O
Saya tidak mengerti di mana Anda memberikan nama file file dan lokasi dalam metode ini? dapatkah seseorang membantu saya melihat kebodohan saya
Giles
4

Jika dalam file log Anda, Anda memiliki tanggal dalam format ini YYYY-MM-DD , maka, untuk menemukan semua entri misalnya, 2011-02-10, Anda dapat melakukan:

grep 2011-02-10 log_file

Sekarang, katakanlah, jika Anda ingin menemukan entri untuk 2011-02-10 dan 2011-02-11, maka, sekali lagi gunakan greptetapi dengan beberapa pola:

grep -E '2011-02-10|2011-02-11' log_file
Barun
sumber
Baik. Ini berfungsi "seperti yang diiklankan" :) ... Namun, grepakan mencari seluruh file, bahkan jika rentang tanggal di awal file. Rata-rata ini menggandakan waktu pencarian, bila dibandingkan dengan "keluar-setelah-item-terakhir-dalam-jangkauan" ... Saya hanya repot menyebutkan ini karena ukuran file 8 GB yang disebutkan dalam pertanyaan, Anda hasil grep waktu hampir identik dengan contoh sed di sini (1 menit 58detik). Inilah tautan ke hasil tes waktu saya: paste.ubuntu.com/573477
Peter.O
1

Bekerja dengan ukuran file ini selalu sulit.

Cara ke depan bisa dengan membagi file ini menjadi beberapa yang kecil, untuk melakukan ini Anda dapat menggunakan perintah split.

split -d -l 50000 ToBigFile.data file_

Meskipun Anda sudah berpisah Anda masih dapat bekerja dengan file seperti jika akan menggunakan bash untuk loop

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

Tapi alih-alih kucing Anda dapat menggunakan grep terbalik untuk menyingkirkan data yang tidak diinginkan, itu tidak relevan untuk ini. (atau jenis penyempurnaan yang Anda butuhkan).

Pada titik ini Anda hanya akan bekerja dengan banyak file yang lebih kecil, dan perintah yang disebutkan di atas akan bekerja lebih baik pada banyak file yang lebih kecil.

Dan setelah selesai, Anda dapat menggunakan perulangan kedua untuk membuat kembali file yang lebih kecil.

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

Pembaruan Karena kami mulai membagi data menjadi beberapa file, akan ada banyak pekerjaan dengan harddisk dan itu membutuhkan waktu. (Dalam pertanyaan ini rupanya 5 menit).

Di sisi lain langkah selanjutnya mungkin akan lebih cepat.

Jadi metode ini mungkin tidak ada gunanya untuk operasi sederhana grep, awk, sed, tetapi jika pola pencarian menjadi lebih rumit itu bisa menjadi lebih cepat.

Johan
sumber
3
Johanm, butuh awk dan sed hanya 1 menit, rata-rata, untuk mencari file log 8 GB di komputer saya, dan pada compuer yang sama, hanya pemisahan file inital, membutuhkan 4 menit 43detik ... :)
Peter.O
Katakanlah Anda dapat memotong waktu awk dan sed sebesar 50% pada file yang lebih kecil. Maka kita masih perlu melakukan lebih dari 10 operasi itu sebelum kita mendapatkan total waktu ... Jadi mungkin pemecahan file bukan ide terbaik untuk beberapa regresi ...
Johan
Script awk dapat (dengan mudah) dimodifikasi untuk menghasilkan 10 hasil pencarian yang berbeda menjadi 10 file .. dalam satu pass tunggal, tetapi itu akan memperlambat pembacaan sementara sebenarnya menghasilkan laporan ... Sed juga bisa melakukan hal yang sama, tetapi seperti yang saya lakukan Sudah disebutkan dalam komentar asoundmove, sed akan gagal jika tanggal / waktu tertentu tidak memiliki entri dalam log (misalnya, Anda mencari per jam) .. Saya menggunakan banyak dan sangat berguna, tetapi memiliki batasannya ... Berikut adalah sed sed FAQ tentang kapan harus menggunakan sed vs awk .. Saya belum tentu setuju dengan semua itu, tapi saya bisa melihat apa yang mereka maksudkan ... sed.sourceforge.net/sedfaq6.html
Peter. O
0
perl -wlne '/^2011-02-24/ .. /^2011-02-25/ and print' log_file
jembatan Charles
sumber
Ini hanya akan mencetak entri log pertama untuk 2011-02-25.
Gilles 'SO- stop being evil'