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
ssedperintah dijalankan di lokal yang sama denganssedperintah menggunakan escaped string (dan denganssedyang sama perintah) misalnya) - jangan lupa tentang karakter baris baru (di sini Anda mungkin ingin memeriksa apakah
$lhsberisi 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).