Apakah mungkin untuk mencocokkan beberapa nomor baris tertentu (bukan rentang) dengan sed?


9

Mempertimbangkan:

echo -e "a\nb\nc\nd\ne\nf\ng\nh" | sed '3,5a test'

Ini akan cocok dengan baris 3, 4 dan 5.

Tetapi saya mencoba untuk mencocokkan hanya baris 3 dan 5 (bukan 4). Dan tambahkan 'tes' setelah mereka.

Jawaban:


9
echo ... | sed -e '3a test' -e '5a test'

Jika operasi lebih kompleks daripada dalam hal ini maka Anda dapat menggunakan struktur seperti ini:

sed 'b pattern; : action; a \
lalala
b end; : pattern; 3b action; 5b action; : end'

Yaitu Anda meletakkan semua perintah yang Anda butuhkan antara b pattern;dan b end;.

Dan Anda menambahkan semua pola Anda (nomor baris atau apa pun) setelahnya : pattern;.

Yang terjadi adalah ini:

  1. Perintah pertama melompati bagian aksi (mungkin lebih mudah untuk membaca jika polanya ada di awal dan b end;langsung sebelum bagian aksi).

  2. Jika suatu pola cocok maka eksekusi melompat ke bagian tindakan. Setelah aksi, bagian eksekusi melompat ke akhir.

Saya mencoba merapikan ini:

sed '3b action; 5b action; b end; : action; a \
lalala
: end'

Dalam satu baris akan seperti:

sed "3b idAction; 5b idAction; b; : idAction; a test"

Portable, Anda perlu menulisnya:

sed '
   3b action
   5b action
   b
   : action
   a\
   lalala'

( btanpa cabang label sampai akhir, jadi Anda tidak perlu endlabel eksplisit , ;adalah karakter yang valid dalam label dalam sedimplementasi standar ).


4
Wow, sediakan subrutin. Cool
— glenn jackman

Wow, bisakah Anda mengembangkannya? Mereka terlihat sangat berguna!
— terdon

yang dengan 'pola' dan 'tindakan' tampaknya sangat baik karena saya tidak perlu mengulangi 'tes' (atau 'lalala'), harus lebih memahami itu tho thx! :)
— Aquarius Power

@terdon Apa yang bisa saya lakukan?
— Hauke ​​Laging

Maksud saya yang kedua terlihat hebat tetapi sulit dimengerti dan jika Anda punya waktu, saya akan menghargai penjelasannya.
— terdon

5

Dengan sed(lihat jawaban @ HaukeLaging )

Dengan awk:

$ echo -e "a\nb\nc\nd\ne\nf\ng\nh" | awk 'NR==3 || NR==5{$0=$0"\ntest"}1;'

Dengan perl:

$ echo -e "a\nb\nc\nd\ne\nf\ng\nh" | perl -pe '$_ .="test\n" if $. == 3 || $. == 5'

Dapat melakukan sedikit perl golf Anda, menggunakan operator "smart match":perl -lnE 'say if $. ~~ @{[3,5]}'
— glenn jackman

@glennjackman ah, ya memang, terima kasih. Saya harus mengakui bahwa saya agak waspada ~~, tidak memahaminya sebaik yang seharusnya. Juga, keduanya saydan ~~perlu perl v> = 5.10 kan?
— terdon

Saya perlu menambahkan 'tes' setelah kalimat itu, saya mengerti sekarang akan lebih baik untuk menjelaskannya sejak awal. Saya baru saja mengedit OP.
— Aquarius Power

@AquariusPower, perl -pE 'say "test" if $. ~~ @{[4,6]}'- ini menambahkan baris: perl's -pmelakukan pencetakan implisit di akhir program yang diberikan.
— glenn jackman

@AquariusPower juga melihat jawaban yang diperbarui.
— terdon

3

Seperti yang dikatakan @HaukeLaging aleady, perintah ini melakukan apa yang Anda inginkan:

sed -e'3a test' -e'5a test'

Sekarang, ini bisa menjadi agak sulit untuk diketik jika Anda ingin mencocokkan, misalnya, 20 baris.

Dalam kasus ini, dengan asumsi shell Anda mendukung ekspansi brace , Anda dapat menggunakan perintah ini sebagai gantinya:

sed -e{3,5}'a test'

(Perhatikan bahwa kurung kurawal dan koma harus tetap tanda kutip.)

Akibatnya, shell akan meneruskan argumen ke -e3a testdan -e5a testke sed, yang persis seperti yang dilakukan perintah pertama.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.