Bagaimana cara mencetak semua kecuali Nth hingga baris terakhir sed?

9
  • Saya ingin melakukan pelengkap / "kebalikan" dari

    sed 13q;d <file.txt
    

    Secara lebih umum, apakah mungkin untuk melakukan pelengkap / terbalik / berlawanan seperti ini sed? Atau hanya untuk regex?

  • Bagaimana saya mencetak semua kecuali baris ketiga hingga terakhir ?. Apakah ini memerlukan dua tacdan menghitung maju sed? Atau adakah cara seduntuk menghitung dari belakang?

isomorfisma
sumber

Jawaban:

12

Bagian 1

Cukup dhapus baris ke-13:

sed '13d' <file.txt

Dan cara umum untuk melakukan pelengkap di atas adalah:

sed '13!d' <file.txt

Bagian 2

Karena itu bisa dilakukan:

sed -n ':a;${P;q};N;4,$D;ba' <file.txt

Perhatikan 4ini satu lebih dari jumlah yang Anda butuhkan. Jadi jika Anda menginginkan baris ke-10 terakhir, ini akan menjadi 11.

Pengujian dengan seq:

$ seq 100 | sed -n ':a;${P;q};N;4,$D;ba'
98
$ 

Mencoba penjelasan

:a        # define label a
${        # match the last line
    P     # print the first line of the pattern space
    q     # quit
}
N         # match all lines: append the next line to the pattern
4,${      # match the range of lines 4 to the end of the file
    D     # delete the first line of the pattern space
}
ba        # match all lines: jump back to label a 

Tambahan berharga Glenn Jackman:

Itu "hanya baris ke-N". Ini adalah "all BUT the Nth line":

sed -n ':a;${s/^[^\n]*\n//;p;q};N;4,${P;D};ba'

bekerja dengan sed GNU, \nurutannya mungkin tidak bekerja dengan sed lainnya.


Saya mencoba ini dengan BSD sed (OSX) dan ternyata tidak cukup berfungsi pada formulir di atas. Masalahnya tampaknya:

  1. ; digunakan untuk memisahkan garis yang umumnya berfungsi, tetapi tidak bekerja setelah label
  2. BSD sed tampaknya membutuhkan ;setelah perintah terakhir dalam {}grup perintah satu baris , sedangkan GNU sed tidak
  3. \nsecara umum dapat digunakan dalam ekspresi reguler, tetapi tampaknya tidak dalam []ekspresi braket. Jadi untuk mengecualikan baris baru, kita dapat menggunakan sesuatu seperti [[:alnum:][:punct:][:graph:][:blank:]], meskipun ini dapat mengecualikan karakter lain (khususnya karakter kontrol lainnya).

Jadi ini adalah upaya untuk versi yang lebih independen dari platform:

sed -n ':a
${s/^[[:alnum:][:punct:][:graph:][:blank:]]*\n//p;q;};N;4,${P;D;};ba'

Tampaknya ini berfungsi di bawah OSX dan Ubuntu.

Trauma Digital
sumber
@jimmij Jawaban lain tentang pertanyaan terkait dalam jaringan SE menyarankan bahwa head/ tailsolusi jauh lebih lambat daripada sedsolusi. Terimakasih Meskipun.
isomorfisma
3
@isomorphismes tidak ada program yang dapat mengetahui jumlah baris dalam file kecuali jika melewati seluruh file. Tidak ada jalan lain untuk itu. Satu-satunya cara untuk menghitung dari bawah adalah membalikkan file dan menghitung dari atas atau menguraikannya dua kali. Jadi kepala / ekor akan cukup cepat.
terdon
@ isomorfisma ... karena mereka ( head/ tail) dioptimalkan untuk melakukan apa yang mereka lakukan.
peterph
@isomorphismes - diedit dengan semua bagian yang Anda butuhkan
Digital Trauma
Bagus! Saya harus mengubah jawaban saya, karena entah bagaimana saya mengharapkannya menjadi lebih rumit. :)
peterph