Saya belajar sed. Semuanya tampak baik-baik saja sampai saya menemukan N (multi-line next). Saya membuat file ini (guide.txt) untuk keperluan latihan / pemahaman / konteks. Berikut adalah isi file tersebut ...
This guide is meant to walk you through a day as a Network
Administrator. By the end, hopefully you will be better
equipped to perform your duties as a Network Administrator
and maybe even enjoy being a Network Administrator that much more.
Network Administrator
Network Administrator
I'm a Network Administrator
Jadi tujuan saya adalah mengganti SEMUA instance dari "Administrator Jaringan" dengan "Pengguna Sistem". Karena instance pertama dari "Administrator Jaringan" dipisahkan oleh baris baru (\ n) Saya perlu operator multi-line berikutnya (N) untuk menambahkan baris yang dimulai dengan "Administrator" dengan baris sebelumnya yang berakhir dengan "Jaringan \ n" . Tidak masalah. Tapi saya juga ingin menangkap semua instance "Network Administrator" lainnya.
Dari penelitian saya, saya telah belajar bahwa saya akan membutuhkan dua perintah substitusi; satu untuk string yang dipisahkan baris baru dan satu untuk yang lain. Juga, ada beberapa jive terjadi karena baris terakhir berisi pertandingan substitusi dan multi-baris berikutnya. Jadi saya membuat ini ...
$ sed '
> s/Network Administrator/System User/
> N
> s/Network\nAdministrator/System\nUser/
> ' guide.txt
Ini mengembalikan hasil ini ...
This guide is meant to walk you through a day as a System
User. By the end, hopefully you will be better
equipped to perform your duties as a System User
and maybe even enjoy being a Network Administrator that much more.
System User
Network Administrator
I'm a System User
Saya berpikir bahwa penggantian satu baris akan menangkap semua contoh "normal" dari "Administrator Jaringan" dan menukar dengan "Pengguna Sistem", sedangkan pernyataan multi-baris akan bekerja dengan baik pada instance yang dipisahkan baris baru, tetapi karena Anda dapat melihatnya dikembalikan, apa yang saya anggap, hasil yang tidak terduga.
Setelah beberapa mengutak-atik, saya mendarat di ...
$ sed '
> s/Network Administrator/System User/
> N
> s/Network\nAdministrator/System\nUser/
> s/Network Administrator/System User/
> ' guide.txt
Dan voila, saya mendapatkan output yang diinginkan dari ...
This guide is meant to walk you through a day as a System
User. By the end, hopefully you will be better
equipped to perform your duties as a System User
and maybe even enjoy being a System User that much more.
System User
System User
I'm a System User
Mengapa ini bekerja dan skrip sed aslinya tidak? Saya benar-benar ingin memahami ini.
Terima kasih sebelumnya atas bantuannya.
Jawaban:
Saat Anda sedang belajar
sed
, saya akan meluangkan waktu untuk menambahkan jawaban @ John1024:1) Harap dicatat bahwa Anda menggunakan
\n
string pengganti. Ini berfungsi di GNUsed
, tetapi bukan bagian dari POSIX, jadi ia akan memasukkan backslash dann
dalam banyak lainnyased
(menggunakan\n
dalam pola portabel, btw).Alih-alih ini saya sarankan untuk melakukan
s/Network\([[:space:]]\)Administrator/System\1User/g
:[[:space:]]
Akan cocok dengan baris baru atau spasi, jadi Anda tidak perlu duas
perintah, tetapi menggabungkannya dalam satu. Dengan mengelilinginya\(...\)
Anda dapat merujuknya di pengganti:\1
Akan diganti dengan apa pun yang cocok di pasangan pertama\(\)
.2) Untuk mencocokkan pola dengan lebih dari dua garis, Anda harus tahu
N;P;D
polanya:Itu
N
selalu menambahkan baris berikutnya (kecuali untuk baris terakhir, itu sebabnya itu "disapa" dengan$!
(= jika bukan baris terakhir; Anda harus selalu mempertimbangkan untuk mengawaliN
dengan$!
menghindari skrip yang diakhiri secara tidak sengaja). Kemudian setelah penggantianP
cetak saja baris pertama dalam ruang pola danD
menghapus baris ini dan memulai siklus berikutnya dengan sisa-sisa ruang pola (tanpa membaca baris berikutnya). Ini mungkin apa yang awalnya Anda maksudkan.Ingat pola ini, Anda akan sering membutuhkannya.
3) Pola lain yang berguna untuk pengeditan multiline, terutama ketika lebih dari dua baris terlibat: Tahan pengumpulan ruang, seperti yang saya sarankan kepada John:
Saya ulangi untuk menjelaskannya:
H
menambahkan setiap baris ke ruang tunggu. Karena ini akan menghasilkan baris baru tambahan sebelum baris pertama, baris pertama harus dipindahkan daripada ditambahkan1h
. Yang berikut ini$!d
berarti "untuk semua baris kecuali yang terakhir, hapus spasi pola dan mulai lagi dari awal". Dengan demikian, sisa skrip hanya dieksekusi untuk baris terakhir. Pada titik ini, seluruh file dikumpulkan di ruang penahanan (jadi jangan gunakan ini untuk file yang sangat besar!) Dang
pindahkan ke ruang pola, jadi Anda bisa melakukan semua penggantian sekaligus seperti Anda bisa dengan-z
opsi untuk GNUsed
.Ini adalah pola lain yang berguna yang saya sarankan untuk diingat.
sumber
Pertama, perhatikan bahwa solusi Anda tidak benar-benar berfungsi. Pertimbangkan file uji ini:
Dan kemudian jalankan perintah:
Masalahnya adalah bahwa kode tidak menggantikan yang terakhir
Network\nAdministrator
.Solusi ini berfungsi:
Kami juga dapat menerapkan ini pada Anda
guide.txt
:Kuncinya adalah terus membaca dalam antrean sampai Anda menemukan satu yang tidak berakhir dengan
Network
. Ketika itu selesai, pergantian bisa dilakukan.Catatan Kompatibilitas: Semua penggunaan
\n
di atas dalam teks pengganti. Ini membutuhkan sed GNU. Ini tidak akan berfungsi pada BSD / OSX sed.[Kiat ujung ke Filipina .]
Versi multiline
Jika ini membantu mengklarifikasi, berikut ini perintah yang sama terbagi atas beberapa baris:
Bagaimana itu bekerja
:a
Ini menciptakan label
a
./Network$/{ $!{N;ba} }
Jika baris ini berakhir dengan
Network
, maka, jika ini bukan baris terakhir ($!
) baca dan tambahkan baris berikutnya (N
) dan cabang kembali ke labela
(ba
).s/Network\nAdministrator/System\nUser/g
Lakukan penggantian dengan baris baru perantara.
s/Network Administrator/System User/g
Buat substitusi dengan perantara kosong.
Solusi yang lebih sederhana (hanya GNU)
Dengan GNU sed ( bukan BSD / OSX), kita hanya perlu satu perintah pengganti:
Dan pada
guide.txt
file:Dalam hal ini,
-z
beri tahu sed untuk membaca hingga karakter NUL pertama. Karena file teks tidak pernah memiliki karakter nol, ini memiliki efek membaca seluruh file sekaligus. Kami kemudian dapat melakukan penggantian tanpa khawatir kehilangan garis.Metode ini tidak baik jika file tersebut berukuran besar (biasanya berarti gigabytes). Jika ukurannya sebesar itu, maka membacanya sekaligus dapat menyusahkan sistem RAM.
Solusi yang bekerja pada GNU dan BSD
Seperti yang disarankan oleh Phillipos , berikut ini adalah solusi portabel:
sumber
Network Administrator
terbagi antara baris pertama dan kedua dari pasangan itu, solusi Anda berhasil membuat substitusi. Kemudian mencetak dua baris dan membaca di pasangan berikutnya. Namun, jika baris kedua dari pasangan pertama berakhir denganNetwork
dan baris pertama dari pasangan kedua dimulai denganAdministrator
, kode tersebut melewatinya. Kode saya menghindari ini dengan membaca dalam baris sampai menemukan kode yang tidak berakhirNetwork
.sed
:\n
Penggantian di dalam tidak ditentukan dalam standar.sed 'H;1h;$!d;x;s/Network\([[:space:]]\)Administrator/System\1User/g'
adalah cara portabel untuk melakukannya.