Bagaimana menjaga 50 baris terakhir dalam logfile

22

Saya mencoba untuk menjaga 50 baris terakhir dalam file saya di mana saya menghemat suhu setiap menit. Saya menggunakan perintah ini:

tail -n 50 /home/pi/Documents/test > /home/pi/Documents/test

Tetapi hasilnya adalah file tes kosong. Saya pikir, itu akan mencantumkan 50 baris terakhir file uji dan memasukkannya ke file uji. Ketika saya menggunakan perintah ini:

tail -n 50 /home/pi/Documents/test > /home/pi/Documents/test2

itu bekerja dengan baik. Ada 50 baris dalam file test2.

Adakah yang bisa menjelaskan di mana masalahnya?

dorinand
sumber
2
Sesuatu seperti rrdtool mungkin lebih tepat untuk menyimpan catatan N (di antara statistik lainnya) seiring waktu.
tangkap
Lihat juga unix.stackexchange.com/a/147620/117549
Jeff Schaller
2
masalah pemotongan klasik
haylem
Jika Anda menggunakan python untuk menghasilkan log, Anda harus melihat ke dalam loggingmodul
Wayne Werner

Jawaban:

30

Masalahnya adalah shell Anda mengatur pipeline perintah sebelum menjalankan perintah. Ini bukan masalah "input dan output", melainkan bahwa konten file sudah hilang bahkan sebelum berjalan. Bunyinya seperti:

  1. Shell membuka >file output untuk menulis, memotongnya
  2. Shell mengatur agar file-descriptor 1 (untuk stdout) digunakan untuk output itu
  3. Shell dieksekusi tail.
  4. tailberjalan, membuka /home/pi/Documents/testdan tidak menemukan apa pun di sana

Ada berbagai solusi, tetapi kuncinya adalah memahami masalahnya, apa yang sebenarnya salah dan mengapa.

Ini akan menghasilkan apa yang Anda cari,

echo "$(tail -n 50 /home/pi/Documents/test)" > /home/pi/Documents/test

Penjelasan:

  • $() disebut substitusi perintah yang dijalankan tail -n 50 /home/pi/Documents/test
  • tanda kutip mempertahankan jeda baris dalam output.
  • > /home/pi/Documents/testmengalihkan keluaran echo "$(tail -n 50 /home/pi/Documents/test)"ke file yang sama.
Rahul
sumber
Terima kasih itu berfungsi dengan baik! Saya punya satu pertanyaan lagi. Bisakah Anda jelaskan bagaimana prosedur Anda bekerja selangkah demi selangkah?
dorinand
1
Tetapi mengapa dalam kasus Anda bash tidak tampil> lebih dulu? Saya tidak mengerti bagaimana bash memproses perintah. Adakah yang bisa menjelaskan?
dorinand
1
> Berada pada perintah echo, jadi dieksekusi ketika perintah echo memulai eksekusi. Itu tidak dapat memulai eksekusi sebelum ditulis. Substitusi variabel adalah apa yang menulis perintah. Ini menjalankan perintah bersarang dan membuat perintah gema dengan mengganti nilainya.
jobermark
Ketika saya mencoba menggunakan yang sama untuk file log 44GB menggunakan 5.000 baris, bukan 50, saya mendapatkan kesalahanbash: xrealloc: cannot allocate 18446744071562067968 bytes
Carmageddon
8

Solusi lain untuk pengalihan file membersihkan file terlebih dahulu adalah dengan menggunakan spongedari paket moreutilsseperti:

tail -n 50 /home/pi/Documents/test | sponge /home/pi/Documents/test
iobender
sumber
6

Ini karena bash memproses pengalihan dengan yang >pertama, menghapus isi file. Kemudian ia menjalankan perintah. Jika Anda ingin menggunakannya >>, 50 baris terakhir akan ditambahkan ke akhir dari apa yang saat ini ada dalam file. Dalam hal ini, Anda harus mengulangi 50 baris yang sama dua kali.

Perintah berfungsi seperti yang diharapkan saat mengarahkan ke file yang berbeda. Berikut adalah salah satu cara untuk menulis 50 baris terakhir file ke file dengan nama yang sama:

tail -50 /home/pi/Documents/test > /home/pi/Documents/test2 && mv /home/pi/Documents/test2 /home/pi/Documents/test

Ini pertama menulis 50 baris terakhir ke file sementara, yang kemudian dipindahkan menggunakan mvuntuk mengganti file asli.

Seperti yang tercantum di komentar, ini tidak akan berfungsi jika file masih terbuka. Memindahkan file juga menciptakan inode baru dan dapat mengubah kepemilikan dan izin. Cara yang lebih baik untuk melakukan ini menggunakan file sementara adalah:

tail -50 /home/pi/Documents/test > /home/pi/Documents/test2 ; cat /home/pi/Documents/test2 > /home/pi/Documents/test

File sementara juga dapat dihapus, meskipun setiap kali ini terjadi isinya akan ditimpa.

clk
sumber
Terima kasih. Bisakah Anda jelaskan langkah demi langkah apa yang dilakukan bash? Saya tidak bisa membayangkan cara kerjanya.
dorinand
tail -50 /home/pi/Documents/test >/tmp/foo && cat /tmp/foo >/home/pi/Documents/test
steve
1
perhatikan bahwa ini tidak akan berfungsi jika file log masih terbuka oleh proses logging (yang akan terus masuk ke file asli yang dihapus). tempfile + move menghasilkan inode baru (memutus semua tautan keras), dan kemungkinan pemilik atau perm yang berbeda. tail ... > temp ; cat temp > orig ; rm -f tempbekerja.
cas
4

Karena Anda telah melihat masalah utama pengalihan shell, berikut adalah cara alternatif untuk memangkas file hingga 50 baris terakhir:

file=/path/to/the/file
n=$(( $(wc -l < "$file") - 50 ))
[[ $n -gt 0 ]] && sed -i 1,${n}d "$file"

Kerja keras dilakukan oleh (GNU) dengan fitur -i"in-place editing", yang bekerja di bawah sampul dengan membuat output dalam file sementara. Sisa garis mengatur matematika untuk operasi sed, yaitu:

  1. hitung baris dalam file ( wc), lalu kurangi 50; tetapkan itu untuk n.
  2. jika n positif, jalankan perintah sed untuk menghapus baris 1 hingga n.
Jeff Schaller
sumber
4
printf '%s\n' '1,$-50d'   w | ed -s /home/pi/Documents/tes

printfdigunakan untuk menyalurkan perintah (satu per baris) ke ed. The edperintah adalah:

  • 1,$-50d - hapus semua kecuali 50 baris terakhir
  • w - tulis file yang dimodifikasi kembali ke disk

Tidak ada pengalihan yang terlibat, sehingga shell tidak dapat menimpa file output sebelum dibaca.

Juga, tidak seperti kebanyakan bentuk pengeditan "di tempat" (yang biasanya hanya mensimulasikan pengeditan "di tempat" dengan membuat file temp dan kemudian mengubah nama file menjadi yang asli), edsebenarnya mengedit file asli - sehingga ia menyimpan inode yang sama ( dan pemilik, grup, dan izin - tempfile + mv akan selalu mengubah inode, dan dapat mengubah yang lain tergantung pada keadaan).

cas
sumber
4

Pada trek yang sedikit berbeda, Anda dapat menggunakan logrotate(8)untuk membuat cadangan file log secara berkala ke file yang diberi nama secara bertahap, dan kemudian menghapus yang lama.

Ini adalah bagaimana file log sistem utama dikelola untuk mencegahnya tumbuh terlalu lama.

CSM
sumber