OK, uma solução geral. A seguinte função bash requer 2k
arguments; cada par consiste em um espaço reservado e um substituto. Cabe a você citar as cordas apropriadamente para passá-las para a função. Se o número de argumentos for ímpar, um argumento vazio implícito será adicionado, o que efetivamente excluirá ocorrências do último espaço reservado.
Nem espaços reservados nem substitutos podem conter caracteres NUL, mas você pode usar C \
-escapes padrão, como
, se precisar de NUL
\
s (e, consequentemente, será necessário escrever \
se desejar \
).
Requer as ferramentas de compilação padrão que devem estar presentes em um sistema do tipo posix (lex e 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"
}
Assumimos que lex
já tenha escapado, se necessário, nos argumentos
mas precisamos escapar de aspas duplas, se presentes. Isso é o que o
segundo argumento para o segundo printf faz. Como a ação padrão ECHO
é cc
, não precisamos nos preocupar com isso.
Exemplo de execução (com horários para os céticos; é apenas um laptop barato):
$ 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
Para entradas maiores, pode ser útil fornecer um sinalizador de otimização para c99
e, para a compatibilidade atual com Posix, seria melhor usar %code% . Uma implementação ainda mais ambiciosa pode tentar armazenar em cache os executáveis gerados em vez de gerá-los a cada vez, mas eles não são exatamente caros para gerar.
Editar
Se você tiver tcc , poderá evitar o incômodo de criar um diretório temporário e aproveitar o tempo de compilação mais rápido que ajudará a entradas de tamanho 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