OK, solusi umum. Fungsi bash berikut membutuhkan 2k
argumen; masing-masing pasangan terdiri dari pengganti dan satu pengganti. Terserah Anda untuk mengutip string dengan tepat untuk meneruskannya ke dalam fungsi. Jika jumlah argumen aneh, argumen kosong implisit akan ditambahkan, yang secara efektif akan menghapus kejadian placeholder terakhir.
Baik penampung atau pengganti tidak boleh mengandung karakter NUL, tetapi Anda dapat menggunakan standar C \
-escapes seperti \0
jika Anda membutuhkan NUL
(dan akibatnya Anda harus menulis \\
jika Anda menginginkan a \
).
Ini membutuhkan alat bantu standar yang harus ada pada sistem seperti posix (lex dan cc).
replaceholder() {
local dir=$(mktemp -d)
( cd "$dir"
{ printf %s\\n "%option 8bit noyywrap nounput" "%%"
printf '"%s" {fputs("%s", yyout);}\n' "${@//\"/\\\"}"
printf %s\\n "%%" "int main(int argc, char** argv) { return yylex(); }"
} | lex && cc lex.yy.c
) && "$dir"/a.out
rm -fR "$dir"
}
Kami berasumsi bahwa \
sudah lolos jika perlu dalam argumen tetapi kami harus lolos dari tanda kutip ganda, jika ada. Itulah yang dilakukan argumen kedua ke printf kedua. Karena lex
tindakan defaultnya adalah ECHO
, kita tidak perlu khawatir tentang hal itu.
Contoh menjalankan (dengan timing untuk skeptis; itu hanya laptop komoditas murah):
$ time echo AB | replaceholder A B B A
BA
real 0m0.128s
user 0m0.106s
sys 0m0.042s
$ time printf %s\\n AB{0000..9999} | replaceholder A B B A > /dev/null
real 0m0.118s
user 0m0.117s
sys 0m0.043s
Untuk input yang lebih besar, mungkin berguna untuk menyediakan flag optimasi cc
, dan untuk kompatibilitas Posix saat ini, akan lebih baik untuk digunakan c99
. Implementasi yang bahkan lebih ambisius mungkin mencoba untuk membuat cache executable yang dihasilkan alih-alih menghasilkan mereka setiap kali, tetapi mereka tidak benar-benar mahal untuk dihasilkan.
Edit
Jika Anda memiliki tcc , Anda dapat menghindari kerumitan membuat direktori sementara, dan menikmati waktu kompilasi yang lebih cepat yang akan membantu pada input berukuran normal:
treplaceholder () {
tcc -run <(
{
printf %s\\n "%option 8bit noyywrap nounput" "%%"
printf '"%s" {fputs("%s", yyout);}\n' "${@//\"/\\\"}"
printf %s\\n "%%" "int main(int argc, char** argv) { return yylex(); }"
} | lex -t)
}
$ time printf %s\\n AB{0000..9999} | treplaceholder A B B A > /dev/null
real 0m0.039s
user 0m0.041s
sys 0m0.031s
tr AB BA
.