Konsep 'Hold space' dan 'Pattern space' dalam sed

87

Saya bingung dengan dua konsep di sed: ruang tahan dan ruang pola. Bisakah seseorang membantu menjelaskannya?

Berikut cuplikan manualnya:

h H    Copy/append pattern space to hold space.
g G    Copy/append hold space to pattern space.

n N    Read/append the next line of input into the pattern space.

Enam perintah ini sangat membingungkan saya.

ChenQi
sumber
4
Cobalah sendiri:echo $'1\n2\n3\n4' | sed -n '1~2h;2~2{p;x;p}'
choroba
4
Jangan bingung, jangan gunakan saja. Untuk apa pun selain substitusi sederhana pada satu baris, Anda harus menggunakan awk, bukan sed. Ruang penahan, ruang pola, dan 95% dari konstruksi bahasa sed ditemukan sebelum awk ketika tidak ada alternatif yang lebih baik. Mereka menjadi usang segera setelah awk ditemukan pada pertengahan 1970-an dan hanya dipertahankan hingga saat ini oleh orang-orang yang menikmati memecahkan masalah menggunakan sintaks arcane seds daripada melakukannya secara sederhana dan cearly in awk. Jika Anda menggunakan lebih dari s, g, dan p (dengan -n) di sed maka Anda hampir pasti menggunakan alat yang salah.
Ed Morton
27
Morton awk bekerja dengan data terstruktur (setiap baris memiliki struktur yang sama). Sed dimaksudkan untuk bekerja dengan data acak mentah. Jadi Anda tidak bisa hanya menggunakan awk dan bukan sed.
Pithikos
5
Saya sangat merekomendasikan membaca info sed. Ini jauh lebih rinci daripada halaman manual telanjang.
Fernando Basso
4
Saya setuju dengan Pithikos. Saya pergi ke jalan kecil seperti yang dilakukan Morton, dan menanyakan diri saya pertanyaan yang sama seperti yang dilakukan Morton. Namun, saya belum bisa mengabaikannya dengan mudah.
eigenfield

Jawaban:

116

Ketika sed membaca file baris demi baris, garis yang telah saat membaca dimasukkan ke dalam pola penyangga (ruang pola). Pola buffer seperti buffer sementara, alas awal tempat informasi saat ini disimpan. Ketika Anda memberi tahu sed untuk mencetak, itu mencetak buffer pola.

Hold buffer / hold space seperti penyimpanan jangka panjang, sehingga Anda dapat menangkap sesuatu, menyimpannya, dan menggunakannya kembali nanti ketika sed memproses baris lain. Anda tidak langsung memproses ruang penahanan, sebaliknya, Anda perlu menyalinnya atau menambahkan ke ruang pola jika Anda ingin melakukan sesuatu dengannya. Misalnya, perintah pcetak hanya mencetak ruang pola. Demikian pula, sberoperasi pada pola ruang.

Berikut ini contohnya:

sed -n '1!G;h;$p'

(opsi -n menekan pencetakan garis otomatis)

Ada tiga perintah di sini: 1!G, hdan $p. 1!Gmemiliki alamat, 1(baris pertama), tetapi !artinya perintah akan dieksekusi di mana saja kecuali di baris pertama. $pdi sisi lain hanya akan dieksekusi di baris terakhir. Jadi yang terjadi adalah ini:

  1. baris pertama dibaca dan disisipkan secara otomatis ke dalam ruang pola
  2. pada baris pertama, perintah pertama tidak dijalankan; hmenyalin baris pertama ke ruang tunggu .
  3. sekarang baris kedua menggantikan apa pun yang ada di ruang pola
  4. pada baris kedua, pertama kita jalankan G, tambahkan konten buffer penahan ke buffer pola, pisahkan dengan baris baru. Ruang pola sekarang berisi baris kedua, baris baru, dan baris pertama.
  5. Kemudian, hperintah memasukkan konten yang digabungkan dari buffer pola ke dalam ruang tunggu, yang sekarang menahan baris dua dan satu terbalik.
  6. Kami melanjutkan ke baris nomor tiga - lanjutkan ke titik (3) di atas.

Akhirnya, setelah baris terakhir dibaca dan ruang penahan (berisi semua baris sebelumnya dalam urutan terbalik) telah ditambahkan ke ruang pola, ruang pola dicetak dengan p. Seperti yang Anda tebak, perintah di atas melakukan persis seperti yang dilakukan tacperintah - mencetak file secara terbalik.

Januari
sumber
3
Apakah opsi G dan h bekerja seperti "potong dan tambahkan" ?? Ini tidak terlihat seperti operasi "salin dan tambahkan".
Senyum
Apa yang ditambahkan dengan pola dan tahan spasi ketika perintah bersarang (tanda kurung kurawal) digunakan? '195,210{/add/p}'… Apakah mungkin untuk mengekstrak baris terakhir dari sekelompok baris yang terlibat dalam sebuah pola?
Sandburg
17

@ Ed Morton: Saya tidak setuju dengan Anda di sini. Saya merasa sedsangat berguna dan sederhana (setelah Anda menguasai konsep pola dan menahan buffer) untuk menghasilkan cara yang elegan untuk melakukan multiline grepping.

Sebagai contoh, mari kita ambil file teks yang memiliki nama host dan beberapa informasi tentang setiap host, dengan banyak sampah di antaranya yang tidak saya pedulikan.

Host: foo1
some junk, doesnt matter
some junk, doesnt matter
Info: about foo1 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter
Info: a second line about foo1 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter
Host: foo2
some junk, doesnt matter
Info: about foo2 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter

Bagi saya, skrip awk untuk mendapatkan baris dengan nama host dan infobaris yang sesuai akan memakan waktu lebih banyak daripada yang dapat saya lakukan dengan sed:

sed -n '/Host:/{h}; /Info/{x;p;x;p;}' myfile.txt

keluarannya terlihat seperti:

Host: foo1
Info: about foo1 that I really care about!!
Host: foo1
Info: a second line about foo1 that I really care about!!
Host: foo2
Info: about foo2 that I really care about!!

(Perhatikan bahwa Host: foo1muncul dua kali di output.)

Penjelasan:

  1. -n menonaktifkan output kecuali dicetak secara eksplisit
  2. pertandingan pertama, menemukan dan menempatkan Host:baris ke dalam buffer penahan (h)
  3. pertandingan kedua, menemukan Info berikutnya: baris, tetapi pertukaran pertama (x) baris saat ini dalam buffer pola dengan buffer penahan, dan mencetak (p) Host:baris, kemudian menukar kembali (x) dan mencetak (p) baris Info:.

Ya, ini adalah contoh sederhana, tetapi saya menduga ini adalah masalah umum yang dengan cepat ditangani oleh sed sederhana satu baris. Untuk tugas yang jauh lebih kompleks, seperti tugas di mana Anda tidak dapat mengandalkan urutan tertentu yang dapat diprediksi, awk mungkin lebih cocok.

Jens Jensen
sumber
2
Dalam kasus ini, Anda bisa menggunakan grep:grep 'Host\|Info'
Pithikos
Jika ada dua baris Info setelah Host tertentu, maka @JensJenson ingin kedua baris Info diawali dengan baris Info. Saya pikir saya akan mengedit jawaban yang sesuai. Pithikos, grep tidak akan cukup.
Aaron McDaid
4
@ JensJenson, awkpadanan kode sed Anda juga cukup pendek:awk '/Host:/{hold=$0}; /Info/{print hold; print;}' myfile.txt
Aaron McDaid
13

Meski @ januari jawaban dan contohnya bagus, tapi penjelasannya belum cukup buat saya. Saya harus mencari dan belajar banyak sampai saya berhasil memahami bagaimana tepatnya sed -n '1!G;h;$p'bekerja. Jadi saya ingin menjelaskan tentang perintah untuk orang seperti saya.

Pertama-tama, mari kita lihat apa yang dilakukan oleh perintah tersebut.

$ echo {a..d} | tr ' ' '\n' # Prints from 'a' to 'd' in each line
a
b
c
d
$ echo {a..d} | tr ' ' '\n' | sed -n '1!G;h;$p'
d
c
b
a

Ini membalikkan input seperti yang tacdilakukan perintah.

sedmembaca baris demi baris, jadi mari kita lihat apa yang terjadi pada ruang patten dan ruang tunggu di setiap baris. Saat hperintah menyalin konten ruang pola ke ruang tunggu, kedua spasi memiliki teks yang sama.

Read line    Pattern Space / Hold Space    Command executed
-----------------------------------------------------------
a            a$                            h
b            b\na$                         1!G;h
c            c\nb\na$                      1!G;h
d            d\nc\nb\na$                   1!G;h;$p

Pada baris terakhir, $pcetakan d\nc\nb\na$yang diformat menjadi

d
c
b
a

Jika Anda ingin melihat ruang pola untuk setiap baris, Anda dapat menambahkan lperintah.

$ echo {a..d} | tr ' ' '\n' | sed -n '1!G;h;l;$p'
a$
b\na$
c\nb\na$
d\nc\nb\na$
d
c
b
a

Saya merasa sangat membantu untuk menonton tutorial video ini Memahami cara kerja sed , karena pria itu menunjukkan bagaimana setiap ruang akan digunakan selangkah demi selangkah. Jarak penahan dirujuk dalam tutorial ke-4, tetapi saya merekomendasikan untuk menonton semua video jika Anda tidak terbiasa sed.

Juga dokumen GNU sed dan tutorial Sed Bruce Barnett adalah referensi yang sangat bagus.

Sanghyun Lee
sumber
2
Saya pikir akan membantu juga untuk menyebutkan bahwa ruang penyimpanan untuk semua tujuan praktis adalah kosong kecuali kita menambahkan sesuatu ke dalamnya.
Naveed