Dengan bash
shell, dalam file dengan baris seperti yang berikut ini
first "line"
<second>line and so on
Saya ingin mengganti satu atau lebih kejadian "line"\n<second>
dengan other characters
dan memperoleh setiap waktu:
first other characters line and so on
Jadi saya harus mengganti string dengan karakter khusus seperti "
dan <
dan dengan karakter baris baru.
Setelah mencari di antara jawaban yang lain, saya menemukan bahwa sed
dapat menerima baris baru di sisi kanan perintah (jadi, other characters
string), tetapi tidak di sebelah kiri.
Apakah ada cara (lebih sederhana dari ini ) untuk mendapatkan hasil ini dengan sed
atau grep
?
text-processing
sed
grep
newlines
BowPark
sumber
sumber
\n
pernyataan ewline Anda membuat sebabnya saya bertanya. orang jarang bertanya apakah mereka bisa melakukans//\n/
apa yang Anda bisa dengan GNUsed
, meskipun kebanyakan orang lainsed
akan menolak pelarian itu di sisi kanan. tetap saja, jalan\n
keluar akan bekerja di sebelah kiri dalam POSIX apa punsed
dan Anda dapat menerjemahkannya dengan mudah seolah-y/c/\n/
olah itu akan memiliki efek yang sama sepertis/c/\n/g
dan karenanya tidak selalu berguna.Jawaban:
Tiga
sed
perintah berbeda :Mereka bertiga membangun di atas
s///
perintah ubstitusi dasar :Mereka juga semua berusaha untuk berhati-hati dalam menangani baris terakhir, karena
sed
cenderung berbeda pada output mereka dalam kasus tepi. Inilah artinya$!
alamat yang cocok dengan setiap baris yang!
bukan yang$
terakhir.Mereka juga semua menggunakan
N
perintah ext untuk menambahkan baris input berikutnya ke pola ruang mengikuti\n
karakter ewline. Siapa pun yang telah lamased
belajar akan belajar untuk bergantung pada\n
karakter ewline - karena satu-satunya cara untuk mendapatkannya adalah dengan meletakkannya secara eksplisit di sana.Ketiganya berusaha untuk membaca input sesedikit mungkin sebelum mengambil tindakan -
sed
bertindak secepat mungkin dan tidak perlu membaca seluruh file input sebelum melakukannya.Meskipun mereka melakukan semuanya
N
, ketiganya berbeda dalam metode rekursi mereka.Perintah Pertama
Perintah pertama menggunakan
N;P;D
loop yang sangat sederhana . Tiga perintah ini terintegrasi untuk POSIX-compatiblesed
dan saling melengkapi satu sama lain dengan baik.N
- seperti yang telah disebutkan, menambahkanN
baris input ext ke pola-ruang setelah\n
pembatas ewline yang dimasukkan .P
- sepertip
; ituP
memecah pola-ruang - tetapi hanya sampai dengan\n
karakter ewline pertama yang terjadi . Maka, diberi input / perintah berikut:printf %s\\n one two | sed '$!N;P;d'
sed
P
hanya satu . Namun, dengan ...D
- sepertid
; ituD
menghapus pola-ruang dan memulai siklus baris lain. Tidak sepertid
,D
menghapus hanya sampai garis tepi pertama yang terjadi\n
di pola-ruang. Jika ada lebih banyak ruang-pola mengikuti\n
karakter ewline,sed
mulailah siklus baris berikutnya dengan yang tersisa. Jikad
dalam contoh sebelumnya diganti denganD
, misalnya,sed
akanP
memecah satu dan dua .Perintah ini hanya muncul untuk baris yang tidak cocok dengan
s///
pernyataan ubstitusi. Karenas///
ubstitusi menghapus\n
ewline yang ditambahkanN
, tidak pernah ada yang tersisa ketikased
D
menghapus pola-ruang.Tes dapat dilakukan untuk menerapkan
P
dan / atauD
secara selektif, tetapi ada perintah lain yang lebih sesuai dengan strategi itu. Karena rekursi ini dilaksanakan untuk menangani garis berturut-turut yang cocok hanya bagian dari aturan pengganti, urutan berturut-turut dari garis pencocokan kedua ujung daris///
ubstitution tidak bekerja dengan baik .:Diberikan masukan ini:
... itu mencetak ...
Namun, itu menangani
...baik baik saja.
Perintah Kedua
Perintah ini sangat mirip dengan yang ketiga. Keduanya menggunakan label
:b
peternakan /t
est (seperti juga ditunjukkan dalam jawaban Joeseph R. di sini ) dan kembali lagi ke sana dengan syarat tertentu.-e :n -e
-sed
skrip portabel akan membatasi:
definisi label dengan\n
ewline atau-e
pernyataan xecution inline baru .:n
- mendefinisikan label bernaman
. Ini dapat dikembalikan kapan saja denganbn
atautn
.tn
-t
perintah est kembali ke label yang ditentukan (atau, jika tidak ada yang disediakan, keluar dari skrip untuk siklus baris saat ini) jika adas///
pengganti karena label itu ditentukan atau karena yang terakhir disebutt
ests berhasil.Dalam perintah ini rekursi terjadi untuk garis yang cocok. Jika
sed
berhasil mengganti pola dengan karakter lain ,sed
kembali ke:n
label dan coba lagi. Jika tidak terjadis///
ubstitusi, cetaksed
pola-ruang dan mulailah siklus-baris berikutnya.Ini cenderung menangani urutan berturut-turut dengan lebih baik. Di mana yang terakhir gagal, ini mencetak:
Perintah Ketiga
Seperti disebutkan, logika di sini sangat mirip dengan yang terakhir, tetapi tes lebih eksplisit.
/"$/bn
- ini adalahsed
ujian. Karenab
perintah ranch adalah fungsi dari alamat ini,sed
hanya akanb
ranch kembali ke:n
setelah\n
ewline ditambahkan dan pola-ruang masih berakhir dengan"
tanda kutip ganda.Ada sedikit yang dilakukan antara
N
danb
mungkin - dengan cara inised
dapat dengan cepat mengumpulkan input sebanyak yang diperlukan untuk memastikan bahwa baris berikut tidak sesuai dengan aturan Anda. Thes///
ubstitution berbeda di sini bahwa itu mempekerjakang
bendera lobal - dan sehingga akan melakukan semua penggantian diperlukan sekaligus. Diberikan input identik perintah ini menghasilkan identik dengan yang terakhir.sumber
DATA
dan bagaimana Anda menerima input teks?<<\DATA\ntext input\nDATA\n
ini dipanggang, tetapi itu hanya teks yang diserahkansed
oleh shell dalam dokumen di sini . Ini akan berfungsi sepertised 'script' filename
atauprocess that writes to stdout | sed 'script'
. Apakah itu membantu?D
setiap baris yang diubah ganda? (Anda menggunakannya sesuai keperluan; mungkin saya tidak tahused
persis)D
karenaD
jika tidakD
menghapus dari apa yang sekarang Anda lihat menjadi dua kali lipat. Saya baru saja mengedit - dan saya akan segera mengembangkannya.D
hal itu.Yah, saya bisa memikirkan beberapa cara sederhana tetapi tidak melibatkan
grep
(yang tidak melakukan pergantian tetap) ataused
.Perl
Untuk mengganti setiap kemunculan
"line"\n<second>
denganother characters
, gunakan:Atau, untuk memperlakukan beberapa kejadian berturut-turut
"line"\n<second>
sebagai satu, dan ganti semuanya dengan satuother characters
, gunakan:Contoh:
The
-00
menyebabkan Perl untuk membaca file dalam "modus ayat" yang berarti bahwa "garis" didefinisikan oleh\n\n
bukan\n
, pada dasarnya, setiap paragraf diperlakukan sebagai garis. Substitusi karena itu cocok dengan satu baris baru.awk
Ide dasar yang sama, kita mengatur pemisah rekaman (
RS
) untuk\n\n
menghirup seluruh file, kemudian pemisah catatan keluaran menjadi nol (jika tidak, baris baru tambahan dicetak) dan kemudian menggunakansub()
fungsi untuk melakukan penggantian.sumber
awk
seharusnyaprint;}' file
. Saya perlu menghindari Perl dan sebaiknya menggunakansed
, toh Anda menyarankan alternatif yang baik.baca seluruh file dan lakukan penggantian global:
sumber
${cmds}
khusus-GNU - kebanyakan yang lainsed
akan memerlukan\n
ewline atau-e
jeda antarap
dan}
. Anda dapat menghindari tanda kurung sama sekali - dan mudah dibawa - dan bahkan menghindari memasukkan\n
karakter ewline tambahan pada baris pertama seperti:sed 'H;1h;$!d;x;s/"line"\n<second>/other characters /g'
sed -n '1{h;n};H; ${x; s/"line"\n<second>/other characters /g; p}'
- namun ini semakin tidak dapat dipelihara.Berikut varian jawaban glenn yang akan berfungsi jika Anda memiliki beberapa kejadian berurutan (hanya bekerja dengan GNU
sed
):Ini
:x
hanya label untuk percabangan. Pada dasarnya, yang dilakukan adalah memeriksa baris setelah substitusi dan jika masih cocok"line"
, itu bercabang kembali ke:x
label (itulah yangbx
dilakukan) dan menambahkan baris lain ke buffer dan mulai memprosesnya.sumber
sed
yang mengambil penanganan label non-POSIX cukup jauh untuk menerima ruang sebagai pembatas untuk deklarasi label. Anda harus mencatat, bahwa yang lainsed
akan gagal di sana - dan akan gagalN
. GNUsed
memecah pedoman POSIX untuk mencetak pola-ruang sebelum berhenti padaN
pada baris terakhir, tetapi POSIX menjelaskan bahwa jika suatuN
perintah dibaca pada baris terakhir tidak ada yang harus dicetak.v
perintah GNU yang saling bertentangansed
tetapi tidak ada op dalam versi GNU 4 dan lebih tinggi.sed -e :x -e '/"line"/{$!N' -e '};s/"line"\n<second>/other characters/;/"line"/bx'
.