Cara menghapus baris kosong mulai dari baris 5

10

Aku punya ini:

sed -i '/^$/d' temp_spec.rb

yang melucuti garis kosong dan berfungsi dengan baik. Bagaimana saya bisa membuatnya hanya melakukan ini untuk baris 5-999 (atau idealnya 5 hingga akhir-file).

Saya mencoba:

sed -n5,999 -i '/^$/d' temp_spec.rb
sed '5,999!d/^$/d' temp_spec.rb

tapi tidak ada yang berhasil (tidak ada kesalahan).

Michael Durrant
sumber
Hanya untuk memastikan: Apakah Anda ingin menjaga baris 1 hingga 4, tidak peduli apakah itu kosong atau tidak, atau Anda ingin menghapus baris 1 hingga 4, tidak peduli apakah itu kosong atau tidak? (Sejauh ini, saya menganggap yang pertama, tetapi perintah kedua yang Anda coba membuat saya bertanya-tanya.)
Uwe

Jawaban:

12

Jika Anda ingin menghapus semua baris kosong yang dimulai dengan baris 5 dan menjaga baris 1 hingga 4, Anda dapat menggunakannya

sed -i '5,${;/^$/d;}' temp_spec.rb

Ini {adalah operator pengelompokan, sehingga perintah pertama 5,${berarti "dari baris 5 hingga akhir input ( $) jalankan perintah berikut hingga pencocokan }". Perintah di antara {dan }lagi dapat diawali dengan alamat, sehingga perintah dalam /^$/dberarti "jika tidak ada antara awal ( ^) dan akhir ( $) dari baris, hapus itu". Perintah sed dapat dipisahkan dengan ;. (Ini adalah fitur sed yang tidak terdokumentasi. Ini didukung oleh sebagian besar implementasi sed, tetapi tidak sepenuhnya portabel .) Seperti dicatat oleh Hauke, ;after {adalah opsional; yang sebelumnya }diperlukan.

Jika Anda ingin menghapus semua baris kosong yang dimulai dengan baris 5 dan juga menghapus baris 1 hingga 4, lebih mudah:

sed -i '1,4d;/^$/d' temp_spec.rb
Uwe
sumber
Bagus. Saya tidak tahu bahwa alamat dapat disarangkan seperti itu. Bagi saya ini juga berfungsi tanpa yang utama ;.
Hauke ​​Laging
Yap, Anda benar tentang yang pertama ;.
Uwe
@ Hauke ​​Laging Anda dapat memisahkan perintah dalam skrip sed dengan ';' alih-alih meletakkannya di baris yang berbeda. Itu adalah fitur "tidak berdokumen".
Predrag Punosevac
4

Opsi lain menggunakan awk:

awk 'NR<5||/./'
Lri
sumber
2
sed '5,${s/^$//; t delete; b end; : delete; d; : end;}' temp_spec.rb

Edit 1:

Saya seharusnya menjelaskan ini, jadi ...

Ini tidak perlu rumit. Saya tidak tahu bahwa rentang alamat diizinkan di dalam {}. Jadi saya harus mengekspresikan "hapus baris kosong" secara berbeda. Perintah inti adalah tcara sed if ... then. Takan lebih mudah tetapi hanya tersedia untuk GNU sed. Saya mengutip halaman manual:

label t: Jika sebagai /// telah melakukan substitusi yang sukses sejak baris input terakhir dibaca dan sejak perintah t atau T terakhir, maka cabang ke label; jika label dihilangkan, cabang ke akhir skrip.

Saya menyalahgunakan sperintah terkenal itu . Ini tidak akan menggantikan apa pun kecuali hanya menguji apakah saluran itu kosong. Jadi itu menggantikan baris kosong dengan baris kosong (bisa menggunakan apa pun sebagai pengganti sebagai garis dihapus pula).

Jika stelah melakukan "penggantian" maka saluran kosong. Dalam hal ini perintah dharus dijalankan. Kalau tidak, tidak ada yang harus dilakukan. Karena ttidak melompat jika ada stindakan saya perlu perintah cabang buntuk melompat ke akhir skrip. : labeladalah target cabang. Seperti gotosaat itu di zaman kegelapan (ketika sed ditemukan ... te-hee).

Pilihan lain adalah s"mengganti" semua baris yang tidak kosong, menjadikan perintah yang slebih rumit tetapi lebih mudah:

sed '5,${s/^\(..*\)$/\1/; t end; d; : end;}' input

^..*$berarti "baris tidak kosong" dan \1berarti "isi tanda kurung pertama".

Hauke ​​Laging
sumber
Sedikit penjelasan demi OP (saya bisa merasakan otak mereka mencoba merangkak keluar melalui telinga membaca ini ...)
vonbrand