GNU/Linux >> Belajar Linux >  >> Linux

Menggabungkan berdasarkan tanggal beberapa file log yang juga menyertakan baris yang tidak bertanggal (misalnya jejak tumpukan)

Sulit. Meskipun dimungkinkan menggunakan date dan bash array, ini benar-benar hal yang akan mendapat manfaat dari bahasa pemrograman yang sebenarnya. Di Perl misalnya:

$ perl -ne '$d=$1 if /(.+?),/; $k{$d}.=$_; END{print $k{$_} for sort keys(%k);}' log*
01:02:03.6497,2224,0022 foo
foo1
2foo
foo3
01:03:03.6497,2224,0022 FOO
FOO1
2FOO
FOO3
01:04:03.6497,2224,0022 bar
1bar
bar2
3bar

Berikut hal yang sama yang tidak diringkas menjadi skrip yang dikomentari:

#!/usr/bin/env perl

## Read each input line, saving it 
## as $_. This while loop is equivalent
## to perl -ne 
while (<>) {
    ## If this line has a comma
    if (/(.+?),/) {
        ## Save everything up to the 1st 
        ## comma as $date
        $date=$1;
    }
    ## Add the current line to the %k hash.
    ## The hash's keys are the dates and the 
    ## contents are the lines.
    $k{$date}.=$_;
}

## Get the sorted list of hash keys
@dates=sort(keys(%k));
## Now that we have them sorted, 
## print each set of lines.
foreach $date (@dates) {
    print "$k{$date}";
}

Perhatikan bahwa ini mengasumsikan bahwa semua baris tanggal dan hanya baris tanggal berisi koma. Jika bukan itu masalahnya, Anda dapat menggunakan ini sebagai gantinya:

perl -ne '$d=$1 if /^(\d+:\d+:\d+\.\d+),/; $k{$d}.=$_; END{print $k{$_} for sort keys(%k);}' log*

Pendekatan di atas perlu menyimpan seluruh isi file dalam memori. Jika itu masalah, ini salah satu yang tidak:

$ perl -pe 's/\n/\0/; s/^/\n/ if /^\d+:\d+:\d+\.\d+/' log* | 
    sort -n | perl -lne 's/\0/\n/g; printf'
01:02:03.6497,2224,0022 foo
foo1
2foo
foo3    
01:03:03.6497,2224,0022 FOO
FOO1
2FOO
FOO3    
01:04:03.6497,2224,0022 bar
1bar
bar2
3bar

Yang ini hanya menempatkan semua baris di antara stempel waktu berturut-turut ke satu baris dengan mengganti baris baru dengan \0 (jika ini bisa ada di file log Anda, gunakan urutan karakter apa pun yang Anda tahu tidak akan pernah ada). Ini diteruskan ke sort lalu tr untuk mendapatkan garis kembali.

Seperti yang ditunjukkan dengan sangat tepat oleh OP, semua solusi di atas perlu dilakukan dan tidak memperhitungkan bahwa file dapat digabungkan. Ini salah satu yang berfungsi tetapi tidak seperti yang lain hanya akan berfungsi pada dua file:

$ sort -m <(perl -pe 's/\n/\0/; s/^/\n/ if /^\d+:\d+:\d+\.\d+/' log1) \
            <(perl -pe 's/\n/\0/; s/^/\n/ if /^\d+:\d+:\d+\.\d+/' log2) | 
    perl -lne 's/[\0\r]/\n/g; printf'

Dan jika Anda menyimpan perintah perl sebagai alias, Anda bisa mendapatkan:

$ alias a="perl -pe 's/\n/\0/; s/^/\n/ if /^\d+:\d+:\d+\.\d+/'"
$ sort -m <(a log1) <(a log2) | perl -lne 's/[\0\r]/\n/g; printf'

Linux
  1. Cara Membuat Zip Banyak File di Linux

  2. Mendapatkan Semua File Yang Telah Dimodifikasi Pada Tanggal Tertentu?

  3. Bagaimana Cara Mengarahkan Stderr Dan Stdout Ke File Yang Berbeda Dan Juga Ditampilkan Di Terminal?

  1. Perintah Untuk Membersihkan File Log Lama?

  2. Dd:Beberapa File Input?

  3. Gabungkan / ubah beberapa file PDF menjadi satu PDF

  1. Hitung baris dalam file besar

  2. sintaks file konfigurasi logrotate - beberapa entri wildcard mungkin?

  3. Ganti nama banyak file untuk menghapus akhiran umum dari nama file