Para lidar de forma robusta com informações variáveis em expressões regulares, você precisa escapar dos metacaracteres da expressão regular. Esta pergunta foi respondida muitas vezes - eu fiz pessoalmente muitas vezes - mas aqui está o básico:
^$*[]\.
^ Esses são metacaracteres de expressão regular básica. Cada um deles tem um significado especial em uma expressão regular como sintaxe e não são interpretados literalmente. O significado de vários deles é, na verdade, dependente da posição e, por isso, às vezes may consegue incluí-los em uma expressão regular sem o escape adequado, mas isso não significa que você deveria - especialmente quando a expressão regular é construída de entrada não validada.
Mas tem mais:
delimiter newline &
^ Esses são caracteres de sintaxe de substituição sed
s///
ubstitution. O delimitador - que é tradicionalmente /
- é variável e sed
interpretará automaticamente como o primeiro caractere após um s
para um novo comando.
A nova linha - no lado esquerdo da expressão regular da declaração - é positivamente inescapável. É inválido lá. A única maneira de substituir uma nova linha é usar o \n
escape - mas a única maneira de obter uma nova linha no espaço padrão que pode ser encontrada em uma expressão regular é colocar uma lá você mesmo - e então isso geralmente não é um problema. No lado direito da s///
ubstitution - o lado replace - a nova linha é passível de escape - como todo o resto - com \
, que é o metacaractere de escape. O mesmo é verdade para &
.
E para criar um script robusto de sed
de variáveis, você precisa escapar dele. Esse é o único caminho. Alterar o delimitador porque você espera que haja um em sua instrução não é um método robusto. Você valida entrada e descarta qualquer chance de erros de sintaxe, ou você evita caracteres de sintaxe para indicar o que pretende. Essas são as duas maneiras de escrever programas robustos - não há outros.
Felizmente, sed
torna isso muito fácil. Como mencionado - a barra invertida \
é o metacaractere de escape e até escapará quando for duplicada. E assim podemos usar sed
para escapar de sed
.
printf %s\n "$regex_field" "$replace_field" |
sed -ne'h;n' -e's|[\&/]|\&|g' \
-ex -e's|[]/\.$^*[]|\&|g' \
-eG -e's|\(.*\)\n\(.*\)|s///|p' |
sed -f- edit_file
Veja? A entrada é separada em novas linhas e, portanto, conforme escrita, não é permitida uma nova linha em $regex_field
ou $replace_field
. Você poderia lidar com isso também, mas isso não acontece e a expectativa é que a entrada seja validada para descartá-la.
Em qualquer caso, as linhas de entrada são alimentadas com o primeiro sed
em pares e h
olds uma cópia da primeira metade de cada par de linhas e pula n
ext para o segundo, quando ele escapa os caracteres relevantes para o lado direito de uma declaração sed
s///
ubstitution. Em seguida, e x
altera seus espaços de retenção e padrão e escapa para o lado esquerdo, antes de G
etting o RHS anexado ao LHS como separado por um delimitador \n
ewline. A última coisa que tem que fazer é adicionar os s///
bits antes de p
rinting o comando escapado para o padrão.
O segundo sed
lê seu arquivo de script em -
(que geralmente é interpretado como padrão, mas você pode querer tentar /dev/fd/0
se não) e então aplica isso script para o seu nome edit_file
.