Saya punya file dengan banyak baris, dan setiap baris memiliki cap waktu di awal, seperti
[Thread-3] (21/09/12 06:17:38:672) logged message from code.....
Jadi, saya sering memeriksa 2 hal dari file log ini.
- Beberapa baris pertama, yang memiliki kondisi global dan waktu mulai juga diberikan.
- Beberapa baris terakhir, yang memiliki status keluar dengan beberapa info lainnya.
Apakah ada perintah tunggal praktis cepat yang dapat membuat saya menampilkan hanya beberapa baris pertama dan terakhir file?
head and tail
berfungsi untuk Anda?N
sed(1)
ahli, tetapi ada cara menyimpan barang untuk digunakan nanti. Mungkin terbayar untuk melihat ke sana. OTOH, saya mungkin akan membuat skrip Perl (atau apa pun) untuk melakukannya jika sering digunakan, karena saya lebih akrab dengan itu.Jawaban:
Anda dapat menggunakan
sed
atauawk
membuatnya dengan satu perintah. Namun Anda akan kehilangan kecepatan, sebabsed
dan bagaimanapunawk
juga harus menjalankan seluruh file. Dari sudut pandang kecepatan, lebih baik membuat fungsi atau setiap waktu untuk kombinasitail
+head
. Ini memang memiliki kelemahan dari tidak bekerja jika input adalah pipa, namun Anda dapat menggunakan substitusi proses, jika shell Anda mendukungnya (lihat contoh di bawah).dan hanya meluncurkannya sebagai
untuk melanjutkan dengan substitusi proses (bash, zsh, ksh like shells saja):
ps. Anda bahkan dapat menambahkan
grep
untuk memeriksa apakah "kondisi global" Anda ada.sumber
-n 10
apakah standarnya, bukan?-n 10
tidak perlu di sini.@rush benar tentang menggunakan head + tail yang lebih efisien untuk file besar, tetapi untuk file kecil (<20 baris), beberapa baris mungkin di-output dua kali.
akan sama-sama efisien, tetapi tidak akan memiliki masalah di atas.
sumber
{head; tail;} < file
bekerja di zsh tetapi gagal di sh.{ head; tail;} < file
selalu berhasil. Maaf atas kebisingannya.head
, bukan shell. POSIXhead
harus membiarkan kursor dalam file melewati 10 baris untuk file biasa. Masalah dapat muncul untukhead
implementasi non-POSIX (versi yang sangat lama dari GNU head dulunya tidak sesuai dalam hal itu, tapi kami berbicara beberapa dekade) atau jika file tidak dapat dicari (seperti pipa atau soket yang dinamai, tetapi kemudian solusi lain akan memiliki masalah yang sama).sudo sh -c '{ head; tail;} < /path/to/file'
The
{ head; tail; }
solusi tidak akan bekerja pada pipa (atau soket atau file non-seekable lainnya) karenahead
bisa mengkonsumsi terlalu banyak data seperti membaca dengan blok dan tidak dapat mencari kembali pada pipa berpotensi meninggalkan kursor di dalam file melampaui apatail
yang dimaksud memilih.Jadi, Anda bisa menggunakan alat yang membaca satu karakter pada waktu seperti shell
read
(di sini menggunakan fungsi yang mengambil jumlah garis kepala dan garis ekor sebagai argumen).atau mengimplementasikan
tail
awk misalnya sebagai:Dengan
sed
:(walaupun berhati-hatilah bahwa beberapa
sed
implementasi memiliki batasan rendah pada ukuran ruang pola mereka, sehingga akan gagal untuk nilai besar dari jumlah garis ekor).sumber
Menggunakan
bash
substitusi proses, Anda dapat melakukan hal berikut:Perhatikan bahwa garis tidak dijamin dalam urutan, meskipun untuk file yang lebih panjang dari sekitar 8 kB, kemungkinan besar akan. Cutoff 8kB ini adalah ukuran khas buffer baca, dan terkait dengan alasan
| {head; tail;}
tidak bekerja untuk file kecil.The
cat >/dev/null
diperlukan untuk menjagahead
pipa hidup. Kalau tidak,tee
akan keluar lebih awal, dan sementara Anda akan mendapatkan outputtail
, itu akan berasal dari suatu tempat di tengah input, bukan akhir.Akhirnya, mengapa
>/dev/null
alih - alih, katakanlah, pindahtail
ke yang lain|
? Dalam kasus berikut:head
stdout dimasukkan ke dalam pipatail
daripada konsol, yang bukan apa yang kita inginkan sama sekali.sumber
tail
harus bekerja lebih lama, tetapi saya berharap (dan memang melihat) gagal sekitar setengah waktu untuk input pendek.tee >(head) >(tail)
alasan yang sama (>(...)
yang merupakan fitur ksh yang sekarang didukung oleh zsh dan bash juga) menggunakan pipa juga. Anda bisa melakukannya... | (trap '' PIPE; tee >(head) >(tail) > /dev/null)
tetapi Anda masih akan melihat beberapa pesan kesalahan pipa yang rusaktee
.tail
adalah orang yang dibunuh oleh SIGPIPE, bukantee
, dantail
tidak menulis ke sebuah pipa. Jadi itu pasti darikill()
, kan? Dan ini hanya terjadi ketika saya menggunakan|
sintaks.strace
mengatakan bahwatee
itu tidak meneleponkill()
... jadi mungkinbash
?seq 100000 | tee >(head -n1) >(tail -n1) > /dev/null
Menggunakan
ed
(yang akan membaca seluruh file ke dalam RAM):sumber
ed -s file <<< $'11,$-10d\n,p\nq\n'
Solusi pertama Stephane dalam fungsi sehingga Anda dapat menggunakan argumen (berfungsi di shell Bourne-like atau POSIX):
Sekarang Anda bisa melakukan ini:
Ini tentu saja mengasumsikan bahwa Anda hanya melihat satu file dan seperti solusi Stephane bekerja (andal) hanya pada file biasa (yang dapat dicari).
sumber
Dengan opsi
-u
(--unbuffered
) dari GNUsed
, Anda dapat menggunakansed -u 2q
sebagai alternatif tanpa buffer untukhead -n2
:(head -n2;tail -n2)
gagal ketika baris terakhir adalah bagian dari blok input yang dikonsumsi olehhead
:sumber
Saya bertemu dengan sesuatu seperti ini hari ini di mana saya hanya membutuhkan baris terakhir dan beberapa baris dari depan sungai dan muncul dengan yang berikut.
Saya membaca ini sebagai: menginisialisasi ruang penahanan dengan isi baris pertama, menambahkan baris 2-3 di ruang penahanan, di EOF menambahkan baris terakhir ke ruang penahanan, menukar ruang penahanan dan pola, dan mencetak pola ruang.
Mungkin seseorang dengan lebih banyak-
sed
fu daripada yang saya dapat mengetahui bagaimana menggeneralisasi ini untuk mencetak beberapa baris terakhir dari aliran yang ditunjukkan dalam pertanyaan ini, tetapi saya tidak membutuhkannya dan tidak dapat menemukan cara mudah untuk melakukan matematika berdasarkan$
alamat dalamsed
atau mungkin dengan mengelola ruang pegang sehingga hanya beberapa baris terakhir yang ada di dalamnya ketikaEOF
tercapai.sumber
Anda dapat mencoba Perl, jika Anda telah menginstalnya:
Ini akan berfungsi untuk sebagian besar file, tetapi membaca seluruh file ke dalam memori sebelum memprosesnya. Jika Anda tidak terbiasa dengan irisan Perl, "0" dalam tanda kurung siku berarti "ambil baris pertama", dan "-3 ...- 1" berarti "ambil tiga baris terakhir". Anda dapat menyesuaikan keduanya untuk kebutuhan Anda. Jika Anda perlu memproses file yang sangat besar (apa yang 'besar' mungkin tergantung pada RAM Anda dan mungkin ukuran swap), Anda mungkin ingin:
mungkin agak lambat, karena membuat irisan setiap iterasi, tapi itu tergantung pada ukuran file.
Kedua perintah harus bekerja baik dalam pipa dan dengan file biasa.
sumber