Saya perhatikan bahwa, jika saya menambahkan \n
pola untuk menggantikan penggunaan sed
, itu tidak cocok. Contoh:
$ cat > alpha.txt
This is
a test
Please do not
be alarmed
$ sed -i'.original' 's/a test\nPlease do not/not a test\nBe/' alpha.txt
$ diff alpha.txt{,.original}
$ # No differences printed out
Bagaimana saya bisa membuatnya bekerja?
sed
regular-expression
utilities
Belmin Fernandez
sumber
sumber
Jawaban:
Dalam panggilan sed sederhana , ia memiliki satu baris teks dalam ruang pola, yaitu. 1 baris
\n
teks yang dibatasi dari input. Baris tunggal di ruang pola tidak memiliki\n
... Itu sebabnya regex Anda tidak menemukan apa pun.Anda dapat membaca banyak baris ke dalam pola-ruang dan memanipulasi hal-hal dengan sangat baik, tetapi dengan upaya yang lebih dari normal .. Sed memiliki seperangkat perintah yang memungkinkan jenis hal ini ... Berikut adalah tautan ke Ringkasan Perintah untuk sed . Itu yang terbaik yang saya temukan, dan membuat saya berputar.
Namun, lupakan ide "satu-liner" begitu Anda mulai menggunakan perintah-mikro sed. Sangat berguna untuk meletakkannya seperti program terstruktur sampai Anda merasakannya ... Anehnya sederhana, dan sama-sama tidak biasa. Anda bisa menganggapnya sebagai "bahasa assembler" dari pengeditan teks.
Rangkuman: Gunakan sed untuk hal-hal sederhana, dan mungkin sedikit lebih, tetapi secara umum, ketika melampaui bekerja dengan satu baris, kebanyakan orang lebih suka sesuatu yang lain ...
Saya akan membiarkan orang lain menyarankan sesuatu yang lain .. Saya benar-benar tidak yakin apa pilihan terbaik (saya akan menggunakan sed, tapi itu karena saya tidak tahu perl cukup baik.)
Ini skrip yang sama, diringkas menjadi apa yang jelas lebih sulit untuk dibaca dan bekerja dengan, tetapi beberapa orang akan dengan ragu menyebut satu kalimat
Ini perintah saya "cheat-sheet"
sumber
t
perintah di sini — ketika tidak diberi label, default untuk percabangan di akhir skrip. Begitused '/^a test$/{$!{N;s/^a test\nPlease do not$/not a test\nBe/;t;P;D}}' alpha.txt
juga persis sama dengan perintah Anda dalam segala situasi. Tentu saja untuk file khusus ini ,sed '/test/{N;s/.*/not a test\nBe/}' alpha.txt
melakukan hal yang sama juga, tetapi contoh pertama saya secara logis setara untuk semua file yang mungkin. Perhatikan juga bahwa\n
dalam string pengganti tidak menghasilkan baris baru; Anda memerlukan garis miring terbalik `\` diikuti oleh baris baru yang sebenarnya untuk melakukan itu.#
perintah tidak terpisahkan dari yang sebelumnya,\n
dalam RHS ofs
). Dengan GNUsed
Anda juga dapat menggunakan-z
untuk menggunakan catatan dibatasi NUL (dan kemudian menghirup seluruh input jika itu teks (yang menurut definisi tidak mengandung NUL)).Gunakan
perl
alih-alihsed
:-pi -e
adalah urutan baris perintah "ganti di tempat" standar Anda, dan -0777 menyebabkan perl untuk menyeruput seluruh file. Lihat perlrun perldoc untuk mencari tahu lebih banyak tentang hal itu.sumber
sed
dan menjawab menggunakan awk atau perl muncul. Saya pikir itu bukan pada topik, karenanya, maaf, tapi saya memecat satu minus.sed
jawaban di atas membuktikan bahwa jawaban Perl ada pada topik.Saya pikir, lebih baik mengganti
\n
simbol dengan simbol lain, dan kemudian bekerja seperti biasa:mis. kode sumber tidak berfungsi:
dapat diubah menjadi:
Jika ada yang tidak tahu,
\n
apakah UNIX mengakhiri baris,\r\n
- windows,\r
- Mac OS klasik. Teks UNIX normal tidak menggunakan\r
simbol, jadi aman digunakan untuk kasus ini.Anda juga dapat menggunakan beberapa simbol eksotis untuk mengganti \ n sementara. Sebagai contoh - \ f (simbol umpan formulir). Anda dapat menemukan lebih banyak simbol di sini .
sumber
\r
dalam argumensed
dengan$(printf '\r')
.$
sebelum string sed untuk mencegahnya mengubah\r
menjadir
. Contoh singkat:sed $'s/\r/~/'
. Contoh lengkap:cat alpha.txt | tr '\n' '\r' | sed $'s/a test\rPlease do not/not a test\rBe/' | tr '\r' '\n'
Semua hal dipertimbangkan, melahap seluruh file mungkin cara tercepat untuk pergi.
Sintaks dasar adalah sebagai berikut:
Pikiran Anda, melahap seluruh file mungkin tidak menjadi pilihan jika file tersebut sangat besar. Untuk kasus seperti itu, jawaban lain yang disediakan di sini menawarkan solusi khusus yang dijamin dapat bekerja pada jejak memori kecil.
Untuk semua situasi hack dan slash lainnya, cukup dengan menambahkan
-e '1h;2,$H;$!d;g'
diikuti olehsed
argumen regex asli Anda cukup banyak menyelesaikan pekerjaan.misalnya
Apa yang
-e '1h;2,$H;$!d;g'
harus dilakukanThe
1
,2,$
,$!
bagian adalah garis penentu yang batas yang garis perintah langsung berikut berjalan pada.1
: Baris pertama saja2,$
: Semua baris mulai dari yang kedua$!
: Setiap baris selain yang terakhirJadi diperluas, inilah yang terjadi pada setiap baris dari input jalur N.
The
g
perintah tidak diberi specifier line, tetapi sebelumnyad
perintah memiliki klausul khusus " Mulai siklus berikutnya. ", Dan ini mencegahg
dari berjalan pada semua lini kecuali yang terakhir.Adapun arti dari setiap perintah:
h
diikuti olehH
s pada setiap salinan baris kata baris masukan ke dalamsed
's ruang ditahan . (Pikirkan buffer teks sewenang-wenang.)d
buang setiap baris untuk mencegah agar baris-baris ini tidak ditulis ke output. The ruang hold namun yang diawetkan.g
mengembalikan akumulasi setiap baris dari ruang tunggu sehinggased
mampu menjalankan regexnya pada seluruh input (daripada secara garis-pada-waktu), dan karenanya mampu cocok pada\n
s.sumber
sed
memiliki tiga perintah untuk mengelola operasi multi-line:N
,D
danP
(membandingkannya dengan yang normaln
,d
danp
).Dalam hal ini, Anda dapat mencocokkan baris pertama dari pola Anda, gunakan
N
untuk menambahkan baris kedua ke ruang pola dan kemudian gunakans
untuk melakukan substitusi Anda.Sesuatu seperti:
sumber
G
,H
,x
...). Lebih banyak garis dapat ditambahkan ke dalam ruang pola dengans
perintah juga.N
perintahAnda bisa tetapi sulit . Saya sarankan beralih ke alat lain. Jika ada ekspresi reguler yang tidak pernah cocok dengan bagian mana pun dari teks yang ingin Anda ganti, Anda dapat menggunakannya sebagai pemisah rekaman awk di GNU awk.
Jika tidak pernah ada dua baris baru berturut-turut dalam string pencarian Anda, Anda dapat menggunakan "mode paragraf" awk (satu atau lebih baris kosong memisahkan catatan).
Solusi mudah adalah dengan menggunakan Perl dan memuat file sepenuhnya ke memori.
sumber
perl -0777 -pe '…' <input-file >output-file
. Untuk memodifikasi file di tempat,perl -0777 -i -pe '…' filename
sed
's-z
pilihan (ditambahkan pada 2012 setelah jawaban yang telah diposting):seq 10 | sed -z 's/4\n5/a\nb/'
.Saya pikir ini adalah solusi sed untuk pencocokan 2 baris.
Jika Anda ingin 3 baris yang cocok maka ...
Jika Anda ingin 4 baris yang cocok maka ...
Jika penggantian bagian dalam perintah "s" menyusutkan garis maka sedikit lebih rumit seperti ini
Jika bagian penggantian menumbuhkan garis maka sedikit lebih rumit seperti ini
sumber
Di sini
/a test/,/Please do not/
dianggap sebagai blok teks (multi baris),c
adalah perintah perubahan diikuti oleh teks barunot a test \nBe
Dalam hal teks yang akan diganti sangat panjang, saya akan menyarankan sintaks ex .
sumber
Hanya perlu sedikit memperluas jendela Anda pada input.
Cukup mudah. Selain substitusi standar; Anda hanya perlu
$!N
,P
danD
di sini.sumber
Selain Perl, pendekatan umum dan praktis untuk mengedit multiline untuk stream (dan file juga) adalah:
Pertama, buat beberapa pemisah baris UNIK yang Anda inginkan, misalnya
Kemudian dalam perintah sed Anda (atau alat lain), Anda ganti \ n dengan $ {S}, seperti
(awk menggantikan pemisah jalur ASCII dengan milik Anda dan sebaliknya.)
sumber
Ini adalah modifikasi kecil dari jawaban pintar xara untuk membuatnya bekerja pada OS X (Saya menggunakan 10.10):
Alih-alih menggunakan secara eksplisit
\r
, Anda harus menggunakan$(printf '\r')
.sumber
printf '\r'
(atauecho -e '\r'
) berfungsi dengan baik, harap perhatikan bahwa Anda bisa menggunakan sintaks shell$'\r'
untuk merujuk pada literal yang lolos. Misalnya,echo hi$'\n'there
akan menggemakan baris baru antarahi
danthere
. Demikian pula, Anda dapat membungkus seluruh string sehingga setiap backslash\
akan lolos dari karakter berikutnya:echo $'hi\nthere'
Saya ingin menambahkan beberapa baris HTML ke file menggunakan sed, (dan berakhir di sini). Biasanya saya hanya menggunakan perl, tetapi saya berada di kotak yang memiliki sed, bash dan tidak banyak lagi. Saya menemukan bahwa jika saya mengubah string menjadi satu baris dan biarkan bash / sed menginterpolasi semuanya \ t \ n berhasil:
Akan lebih bersih memiliki fungsi untuk menghindari tanda kutip ganda dan garis miring, tetapi terkadang abstraksi adalah pencuri waktu.
sumber
GNU
sed
memiliki-z
opsi yang memungkinkan untuk menggunakan sintaks yang coba diterapkan OP. ( halaman manual )Contoh:
Waspada: Jika Anda menggunakan
^
dan$
mereka sekarang cocok dengan awal dan akhir garis dibatasi dengan karakter NUL (tidak\n
). Dan, untuk memastikan kecocokan pada semua\n
baris ( -pisah) Anda diganti, jangan lupa untuk menggunakang
bendera untuk pergantian global (miss/.../.../g
.).Penghargaan: @ stéphane-chazelas pertama kali disebutkan -z dalam komentar di atas.
sumber
Sed memecah input pada baris baru. Itu membuat hanya satu baris per loop.
Oleh karena itu tidak ada cara untuk mencocokkan
\n
(baris baru) jika ruang pola tidak mengandungnya.Ada cara, meskipun, Anda dapat membuat sed menjaga dua garis berturut-turut dalam ruang pola dengan menggunakan loop:
Tambahkan setiap pemrosesan yang dibutuhkan antara N dan P (menggantikan
l
).Dalam hal ini (2 baris):
Atau, untuk tiga baris:
Itu dengan asumsi jumlah baris yang sama akan diganti.
sumber