GNU/Linux >> Belajar Linux >  >> Linux

Bagaimana Cara Memastikan Bahwa String Diinterpolasi Ke Substitusi `sed` Lolos dari Semua Metachars?

Saya memiliki skrip yang membaca aliran teks dan menghasilkan file perintah sed yang kemudian dijalankan dengan sed -f . Perintah sed yang dihasilkan seperti:

s/cid:[email protected]/https://mysite.com/files/1922/g
s/cid:[email protected]/https://mysite.com/files/1923/g
s/cid:[email protected]/https://mysite.com/files/1924/g

Asumsikan skrip yang menghasilkan ssed perintahnya seperti:

while read cid fileid
do
    cidpat="$(echo $cid | sed -e s/\./\\./g)"
    echo 's/'"$cidpat"'/https://mysite.com/files/'"$fileid"'/g' >> sedscr
done

Bagaimana saya bisa meningkatkan skrip untuk memastikan semua metakarakter regex di cid string diloloskan dan diinterpolasi dengan benar?

Jawaban yang Diterima:

Untuk keluar dari variabel yang akan digunakan di sisi kiri dan sisi kanan s perintah di ssed (di sini $lhs dan $rhs masing-masing), Anda akan melakukan:

escaped_lhs=$(printf '%sn' "$lhs" | sed 's:[][\/.^$*]:\&:g')
escaped_rhs=$(printf '%sn' "$rhs" | sed 's:[\/&]:\&:g;$!s/$/\/')

sed "s/$escaped_lhs/$escaped_rhs/"

Perhatikan bahwa $lhs tidak boleh berisi karakter baris baru.

Artinya, di LHS, lepas semua operator regexp (][.^$* ), karakter yang lolos itu sendiri ( ), dan pemisah (/ ).

Di RHS, Anda hanya perlu keluar dari & , pemisah, garis miring terbalik, dan karakter baris baru (yang Anda lakukan dengan menyisipkan garis miring terbalik di akhir setiap baris kecuali baris terakhir ($!s/$/\/ )).

Itu mengasumsikan Anda menggunakan / sebagai pemisah di ssed . Anda s perintah dan bahwa Anda tidak mengaktifkan RE Diperpanjang dengan -r (GNU ssed /ssed /ast /busybox sed ) atau -E (BSD, ast , GNU terbaru, busybox terbaru) atau PCRE dengan -R (ssed ) atau RE yang Ditingkatkan dengan -A /-X (ast ) yang semuanya memiliki operator RE ekstra.

Beberapa aturan dasar saat menangani data arbitrer:

  • Jangan gunakan echo
  • kutip variabel Anda
  • pertimbangkan dampak lokal (terutama rangkaian karakternya:penting agar melarikan diri ssed perintah dijalankan di lokal yang sama dengan ssed perintah menggunakan escaped string (dan dengan ssed yang sama perintah) misalnya)
  • jangan lupa tentang karakter baris baru (di sini Anda mungkin ingin memeriksa apakah $lhs berisi apapun dan mengambil tindakan).

Pilihan lain adalah menggunakan perl bukannya ssed dan berikan string di lingkungan dan gunakan Q /E perl regexp operator untuk mengambil string secara harfiah:

A="$lhs" B="$rhs" perl -pe 's/Q$ENV{A}E/$ENV{B}/g'

perl (secara default) tidak akan terpengaruh oleh set karakter lokal karena, di atas, ini hanya menganggap string sebagai array byte tanpa mempedulikan karakter apa (jika ada) yang mungkin diwakilinya untuk pengguna. Dengan ssed , Anda dapat mencapai hal yang sama dengan memperbaiki lokal ke C dengan LC_ALL=C untuk semua ssed perintah (meskipun itu juga akan memengaruhi bahasa pesan kesalahan, jika ada).

Terkait:Menggunakan sed dengan karakter khusus?
Linux
  1. Bagaimana Cara Mengganti String Dalam File?

  2. Bagaimana Cara Menggunakan Sed Untuk Mengganti String Multi-baris?

  3. Bagaimana Mengganti String Dengan String Yang Mengandung Slash Dengan Sed?

  1. Cara mengganti string dalam banyak file di baris perintah linux

  2. Cara memindahkan semua file termasuk file tersembunyi ke direktori induk melalui *

  3. Bagaimana Anda menentukan perintah aktual yang disalurkan ke Anda?

  1. Cara menghapus semua file yang dimulai dengan string tertentu di Linux

  2. Bagaimana saya bisa yakin bahwa saya telah menyambungkan perangkat ke port USB 3?

  3. Cara menangkap semua disk yang tidak memiliki sistem file