Seberang ekor: semua baris kecuali n baris terakhir

36

Bagaimana saya bisa membuang n baris terakhir file dengan filter baris perintah unix?

Itu akan menjadi semacam kebalikan dari tail: tailmembuang n baris pertama tetapi pipa sisanya melalui, tapi saya ingin perintah untuk mem-pipe semuanya kecuali n baris terakhir.

Sayangnya saya belum menemukan yang seperti itu - headtidak membantu juga. EDIT : Setidaknya di Solaris tidak perlu argumen negatif.

Pembaruan: Saya sebagian besar tertarik pada solusi yang berfungsi untuk file besar, yaitu file log, di mana Anda mungkin ingin memeriksa apa yang terjadi pada menit terakhir.

Hans-Peter Störr
sumber
FYI saat menggunakan head: Dengan menempatkan '-' di depan angka dengan opsi -n, ia mencetak semua baris dari setiap file tetapi bukan baris N terakhir seperti yang ditunjukkan di bawah ini,
G Koe

Jawaban:

38

Jika Anda memiliki GNU head, Anda dapat menggunakan

head -n -5 file.txt

untuk mencetak semua kecuali 5 baris terakhir file.txt.

Jika head -ntidak ada argumen negatif, cobalah

head -n $(( $(wc -l file.txt | awk '{print $1}') - 5 )) file.txt
pengguna570500
sumber
11
(dan berdoalah file.txtsetidaknya enam baris panjang ...)
CVn
1
Sayangnya, versi non-GNU ini juga tidak berfungsi dengan stream
Armand
1
@ MichaelKjörling Setidaknya di ubuntu, itu tidak masalah. Jika file memiliki garis kurang dari yang ditentukan dalam head, output kosong dikembalikan, tanpa kesalahan.
Alphaaa
Jika saya tidak salah kepala -n 5 akan mencetak 5 baris pertama, tidak semua kecuali 5 terakhir ...
pypmannetjies
8
head file.txt               # first 10 lines
tail file.txt               # last 10 lines
head -n 20 file.txt         # first 20 lines
tail -n 20 file.txt         # last 20 lines
head -20 file.txt           # first 20 lines
tail -20 file.txt           # last 20 lines
head -n -5 file.txt         # all lines except the 5 last
tail -n +5 file.txt         # all lines except the 4 first, starts at line 5
Kjetil S.
sumber
1
Apa yang ditambahkan ini yang tidak dijawab dalam jawaban yang diterima? Juga, seperti jawaban Anda yang lain, beberapa baris penjelasan jawaban Anda akan sangat meningkatkannya.
music2myear
1
ringkasan yang sangat bagus
ruanhao
5

Berikut cara sederhana untuk menghapus baris terakhir, yang berfungsi pada BSD, dll.

sed '$d' input.txt

Ekspresi berbunyi "pada baris terakhir, hapus itu". Baris lain akan dicetak, karena itu adalah sedperilaku default.

Anda dapat mengaitkannya bersama untuk menghapus beberapa baris

sed '$d' input.txt | sed '$d' | sed '$d'

Memang agak berat tangan, memang, tetapi hanya satu pemindaian melalui file.

Anda juga dapat melihat ini, untuk jawaban lebih lanjut: https://stackoverflow.com/questions/13380607/how-to-use-sed-to-remove-last-n-lines-of-a-file

Berikut ini adalah satu-liner yang diadaptasi dari salah satu favorit saya di sana:

N=10
sed -n -e ':a' -e "1,$N!{P;N;D;};N;ba"

Saya senang menguraikan yang satu itu, dan saya harap Anda juga melakukannya (: Ia melakukan buffer Nline saat memindai, tetapi sebaliknya cukup efisien.

jwd
sumber
3

Saya ingin tahu mengapa menurut Anda headbukan pilihan:

~$ man head
...
-n, --lines=[-]K
        print the first K lines instead of the first 10; 
        with the leading `-', print all but the last K lines of each file

Ini sepertinya sesuai dengan tujuan Anda, menggunakan, misalnya:

head -n -20 yourfile.txt
Anders R. Bystrup
sumber
5
Perhatikan bahwa ini hanya berlaku untuk GNU head. BSD headtidak memiliki opsi ini, jadi jawaban ini tidak akan berfungsi pada Solaris atau Unix lain tanpa GNU coreutils. OP secara khusus menandai ini dengan Unix dan Unix-Utils juga.
slhck
2
@ Slhck Belum lagi fakta bahwa OP menyebutkan bahwa ini untuk Solaris.
CVn
Sayangnya seseorang menghapus saya menyebutkan Solaris. Tetapi saya harus menyebutkan bahwa versi kepala tidak mendukung itu.
Hans-Peter Störr
1
Maaf semuanya Tidak memperhatikan Solaris, saya juga tidak mengetahui berbagai versi kepala.
Anders R. Bystrup
1
@hstoerr Solaris sekarang ada di tag Anda :)
slhck
0

Cara lain untuk melakukannya jika tail -ntidak akan menerima argumen negatif adalah

tac file.txt | tail -n +6 | tac

Ini akan menghapus 5 baris terakhir

atw31337
sumber
Terima kasih! Itu ide bagus yang belum ada yang sampai sejauh ini. Sayangnya itu akan sangat tidak efisien untuk usecase yang ada dalam pikiran saya dengan pertanyaan ini: jika itu file besar, itu tidak hanya akan sepenuhnya dibaca melalui satu atau lebih kali, seperti dengan solusi lain, tetapi mungkin juga akan ditulis untuk disk ke file sementara oleh tac jika tidak muat ke dalam memori.
Hans-Peter Störr
@ Hans-Peter Sangat benar. Memutuskan untuk menulis skrip python3 untuk itu. Coba github.com/atw31337/donkey ini . Saya sarankan menggunakan opsi output. Mereka berjalan jauh lebih cepat daripada menggunakan arahan ulang.
atw31337
Ditulis dengan baik! Namun, ia membaca file dua kali, yang sebenarnya tidak perlu jika Anda buffer n baris terakhir, dan ini merupakan masalah pada file besar. Secara pribadi, saya tidak membutuhkan itu lagi, tetapi jika Anda senang memperbaikinya dan orang lain membutuhkannya ... Lagi pula, ada beberapa suka dan bookmark pada pertanyaan.
Hans-Peter Störr
@ Hans-Peter. Ukuran buffer akan tergantung pada jumlah garis yang akan dihapus. Ini bisa menjadi masalah jika sejumlah besar baris perlu dihapus dari file. Untuk menghindari masalah terkait memori, saya menulis ulang skrip untuk menggunakan metode penghitungan baris dengan nilai n tinggi dan metode buffering dengan nilai n lebih rendah; namun, setelah mengujinya pada file yang sangat besar, metode penghitungan baris asli masih lebih cepat. Tampaknya overhead manajemen buffer lebih tinggi daripada jumlah baris yang dihitung ... atau saya hanya melewatkan sesuatu.
atw31337
Bagus, tetapi untuk BSD-varian Mac OS X tidak ada perintah tac secara default. :( Jenis ini mengalahkan use case.
ingyhere