Bagaimana perintah substitusi 'sed' ini dengan banyak tanda @ berfungsi?

8

Adakah yang bisa menjelaskan cara sedkerja perintah ini ?

sed 's@+@ @g;s@%@\\x@g' | xargs -0 printf "%b"
Raj
sumber
3
Cara normal untuk melakukan ini adalah menggunakan garis miring, tetapi itu mungkin menjadi rumit jika Anda mencari dan mengganti sesuatu dengan garis miring. Itu tidak terjadi di sini, jadi meskipun itu baik-baik saja itu membingungkan pemelihara masa depan seperti Anda.
Thorbjørn Ravn Andersen
2
... dan membimbing mereka untuk mempelajari sesuatu yang baru tentang sedcara ini! :)
hidangan penutup

Jawaban:

15

Sebagai tambahan, perintah pengganti biasanya ditulis sebagai s/pattern/replacement/options. Namun, itu tidak perlu digunakan /- Anda dapat menggunakan karakter lain jika nyaman, jadi bisa jadi s@pattern@replacement@optionsatau s:foo:bar:g. s@+@ @gseperti s/+/ /g- ganti semua +dengan spasi. Demikian pula s@%@\\x@gmenggantikan semua %dengan \x(backslash tunggal adalah karakter pelarian di sed, jadi Anda perlu dua untuk mendapatkan backslash yang sebenarnya).

String seperti foo+%2Fbarakan menjadi foo \x2Fbar. printf "%b"akan memperluas urutan backslash-escaped seperti \x2F(karakter ASCII yang nilai heksadesimalnya 2F, yaitu /) untuk akhirnya memberi Anda foo /bar.

muru
sumber
2
Secara singkat, URL -> nama file decoder.
Thorbjørn Ravn Andersen
10

Perintah yang Anda tanyakan tentang penguraian +es dan %urutan dari URL bukan hanya sebuah sedperintah, ini adalah pipa yang memproses input sed, lalu mengirimnya ke pipaxargs untuk diproses lebih lanjut. Pertama mari kita lihat sedperintahnya:

sed 's@+@ @g;s@%@\\x@g'

Anda mungkin lebih terbiasa melihatnya dengan /daripada @sebagai pemisah, yang bisa dengan mudah dilakukan di sini tanpa kerumitan karena tidak /muncul dalam pola pencarian maupun teks pengganti. Perintah ini setara:

sed 's/+/ /g;s/%/\\x/g'

Seperti /, @adalah karakter tanda baca yang sangat baik untuk sed.

Di setiap baris input:

  1. s@+@ @g( s/+/ /g) Mengganti ( s) kemunculan +dengan spasi. Ini memengaruhi semua +es pada baris ( g), bukan hanya yang pertama.

  2. ; mengakhiri aksi ("perintah") dan memungkinkan Anda menentukan yang lain di "skrip" yang sama.

  3. s@%@\\x@g( s/%/\\x/g) pengganti ( s) kejadian %dengan \x. Seperti sebelumnya, ini bertindak pada semua, bukan hanya yang pertama dari setiap baris ( g).

    Di \\xdalam \\hanya mewakili satu \karena \memiliki arti khusus untuk sed. Arti istimewanya sebenarnya adalah sebagai karakter yang Anda gunakan untuk menghilangkan makna khusus dari karakter lain yang muncul setelahnya yang seharusnya memiliki makna khusus. Jadi harus diloloskan sebagai \\.


Sekarang mari kita lihat xargsperintah, yang tujuannya dijalankan printf.

xargsmembangun baris perintah. Jika Anda menjalankan , di mana satu kata atau lebih, berjalan dengan argumen baris perintah tambahan yang dibaca dari inputnya. Dalam hal ini, input ke adalah output dari , karena pipa ( ). Biasanya menginterpretasikan spasi putih apa pun dalam inputnya untuk berarti bahwa teks sebelum dan sesudahnya merupakan argumen yang terpisah, tetapi opsi membuatnya memecah argumen pada kemunculan karakter nol sebagai gantinya.xargs command...command...xargscommand...xargssed|xargs-0

Dalam penggunaan perintah yang dimaksudkan, karakter nol tidak akan muncul dan xargsakan berjalan printf %bhanya dengan satu argumen baris perintah tambahan, output dari sedperintah. Dengan demikian, meskipun tidak setara secara umum, dalam hal ini seluruh pipa mungkin telah ditulis seperti ini menggunakan substitusi perintah alih-alih xargs:

printf '%b\n' "$(sed 's/+/ /g;s/%/\\x/g')"

Adapun apa printfyang dimaksudkan untuk dilakukan di sini, seperti Muru mengatakan yang %bmengkonsumsi Format specifier dan mencetak argumen (seperti %s) tapi menyebabkan lolos backslash - dari jenis yang sedperintah di sisi kiri pipa ditulis untuk menghasilkan - untuk diterjemahkan ke dalam karakter yang mereka wakili .

Misalkan saya menjalankan perintah itu dan lulus http://foldoc.org/debugging%20by%20printfsebagai input. Saya mendapatkan http://foldoc.org/debugging by printfsebagai output, karena %20urutan diterjemahkan ke dalam spasi.

Eliah Kagan
sumber
3

Itulah keindahannya sed , itu berlaku paradigma untuk dirinya sendiri ... Setelah perintah (seperti satau tratau tidak), karakter berikutnya dianggap pemisah.

Anda harus memilih dengan bijak untuk menghindari gangguan pada shell dan perintah itu sendiri, dan menjaga hal itu mudah dibaca, tetapi sangat valid untuk menulis sesuatu yang mengerikan seperti:

echo 'arrival' | sed srarbrg

... dan dapatkan brrivbl hasilnya, itulah yang Anda harapkan. Anda bisa bersenang-senang membuatnya benar-benar samar, seperti di:

echo 'arrival' | sed s\fa\fb\fg   # \f is form feed, chr(12)

Penggunaan umum adalah menggunakan slash sebagai pembatas, tetapi ketika ekspresi Anda mengandung pembatas, itu membuatnya lebih mudah untuk mengambil maksudnya. Pembatas Anda bisa berupa apa saja dalam rentang ASCII8 (pembatas multibyte seperti £memancing kesalahan).

Ingat saja tujuannya adalah untuk membuat segalanya lebih mudah, tidak lebih samar.

Marabiloso
sumber
Berjalan dengan ide samar, ini adalah perintah sed yang valid, meskipun itu tidak melakukan apa pun yang berguna:sed "snack is an apple or something" <<< "I sed your snack is an apple or something"
wjandrea
Bagus! Ya, Anda dapat menggunakan sedperintah sebagai permainan asah otak juga, seberapa serakah itu?
Marabiloso