SED ganti lintas banyak baris

11

Saya mencoba menemukan tiga baris ini:

<!--
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
-->

dan menggantinya dengan:

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

Ketika saya mencoba

sudo sed -i 's:<!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->:<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />:' /myfile.xml

Tidak menemukannya, saya juga mencoba meletakkan \ n di dalamnya, tetapi tetap tidak berhasil:

sudo sed -i 's:<!--\n <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />\n -->:<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />:' /myfile.xml

Ini tidak membuang kesalahan apa pun itu hanya tidak menghilangkan komentar pada baris. Saran apa pun akan membantu terima kasih!

Doug Molineux
sumber

Jawaban:

6

sed membaca setiap baris secara bergantian, sehingga tidak akan pernah cocok dengan pola multiline kecuali Anda mendorongnya ke arah yang benar. The Nperintah membaca satu baris dari input dan menambahkan ke ruang pola.

sed -i -e '/^<!--$/ {
    N; /\n<Connector port="8009" protocol="AJP\/1\.3" redirectPort="8443" \/>$/ {
        N; /\n-->$/ {
            s/^<!--\n//; s/\n-->$//
        }
    }
}' /myfile.xml

Boleh dibilang, jika Anda membutuhkan perintah selain s, maka Anda harus beralih dari sed dan ke awk atau perl. Berikut cuplikan Perl yang sedikit lebih fleksibel yang mengatasi komentar multiline dengan cara yang lebih umum.

perl -i -pe '
    if (/<!--/) { $_ .= <> while !/-->/;
        s[<!--\n(<Connector port="8009" protocol="AJP/1\.3" redirectPort="8443" />)\n-->][$1];
    }' /myfile.xml
Gilles 'SANGAT berhenti menjadi jahat'
sumber
6

Sed bekerja berdasarkan garis demi garis. Itu dapat dibuat untuk bekerja pada banyak baris, tetapi tidak dirancang seperti itu - dan menurut saya itu jelas menunjukkan ketika Anda mencoba untuk menggunakan seperti itu. Tetapi jika Anda memutuskan untuk pergi dengan cara itu Anda mungkin harus menggunakan register. Periksa beberapa solusi untuk /programming/1251999/sed-how-can-i-replace-a-newline-n untuk melihat bagaimana hal itu dapat dilakukan.

Saya lebih suka menggunakan perl daripada sed untuk tugas semacam ini (multi-line-oriented, maksud saya). Pelat yang harus Anda tambahkan sebelum pencarian-dan-ganti ( BEGIN...) tidak jelas, tetapi regex tampaknya lebih bersih bagi saya:

perl -i.bak -pe 'BEGIN{undef $/;} s/<!--string-->/string/smg' file.xml

Atau, menggunakan pengelompokan untuk mempersingkat ekspresi dan untuk memungkinkan Anda menggunakan regex di sana:

perl -i.bak -pe 'BEGIN{undef $/;} s/<!--(string_or_regex)-->/\1/smg' file.xml

Ini harus berfungsi baik pada kejadian dengan dan tanpa baris baru antara penanda komentar dan kode yang akan dihapus komentar.

Diadaptasi dari:

/programming/1030787/multiline-search-replace-with-perl

Eduardo Ivanec
sumber
Terima kasih atas bantuan Anda, sepertinya itu menyebalkan, saya memutuskan untuk menggunakan solusi
Doug Molineux
3

Berikut adalah deskripsi perintah multiline di SED: http://docstore.mik.ua/orelly/unix/sedawk/ch06_01.htm

Rasa sakit di pantat. Anda mungkin ingin mengikuti saran Eduardo dan menggunakannya perl -i -p -esebagai gantinya.

Hipn
sumber
Saya tidak akan menautkan ke salinan materi yang dilindungi hak cipta tanpa izin.
Mark Wagner
1
  • /<\!--/ : string yang cocok
  • :X : ini adalah label untuk perintah cabang "b"
  • /-->/ : string yang cocok
  • s@...@...@p : strip "<! -", "->" dan hasil cetak
  • d : hapus ruang pola dan mulai siklus baru
  • N : jika tidak cocok dengan / -> / lalu tambahkan baris
  • bX : cabang ke: label X
  • p : cukup cetak string yang tidak cocok dengan / <! - /

sed -rn '
/<!--/ {
    :X
    /-->/ {
        s@<!--\s*(<.+/>)\s*-->@\1@p
        d
    }
    N
    bX
};p'

dan metode kedua ini adalah sederhana salin & tempel substitusi kata demi kata untuk file teks berukuran kecil biasa (perlu file skrip shell)

#!/bin/bash

# copy & paste content that you want to substitute

AA=$( cat <<\EOF | sed -z -e 's#\([][^$*\.#]\)#\\\1#g' -e 's#\n#\\n#g'
<!--
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
-->
EOF
)

BB=$( cat <<\EOF | sed -z -e 's#\([&\#]\)#\\\1#g' -e 's#\n#\\n#g'
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
EOF
)

sed -z -i 's#'"${AA}"'#'"${BB}"'#g' *.xml   # apply to all *.xml files
mug896
sumber
1) Terima kasih atas jawaban Anda. 2) Memasukkan hanya potongan kode tidak terlalu oke, akan jauh lebih baik jika Anda menjelaskan, apa fungsinya, dan bagaimana.
peterh