Por que seu comando falha:
Você fez:
sed 's/\([^\]\)&/\&/g' <<< "${text}"
-
[^\]\
corresponde a qualquer caractere, exceto\
, e coloca isso no grupo correspondente 1, então&
corresponde a um literal&
. Portanto, paraone&two\&three
, isso corresponderá ae
antes do primeiro&
, coloque isso no grupo capturado 1. Para o&
antes dethree
, isso não será correspondido, pois\
é antes de&
-
Na substituição você usou
\&
, então a saída se tornaone\e&two\&three
porque:-
é substituído por
e
- dois
\
s são tratados como\
. que nos dáe\
até agora - , então
&
corresponderá à correspondência completa, ou seja,e&
, ou seja,&
não será ignorado, como você estava pensando
-
-
Assim, a parte correspondente, por exemplo,
e&
, é substituída pore\e&
Você obteria o resultado desejado se estivesse usando outro
\
antes de&
(Como dois\
fazem um\
, então você precisa de um antes de&
também:sed 's/\([^\]\)&/\\&/g' <<<"${text}"
Como o
sed
do Ubuntu suporta ERE (Expressão Regular Estendida), você pode usar a opção-E
ou -r
para permitir que se livre do()
s durante a captura:sed -E 's/([^\])&/\\&/g' <<<"${text}"
Abordagem alternativa:
Primeiro, remover \
s antes de todo &
s e, em seguida, adicionar \
antes de todo &
:
sed -E 's/[\]+(&)//g; s/&/\&/g'
Isso é composto de duas declarações sed
:
-
s/[\]+(&)//g
remove todos os\
s antes de&
na string (linha) -
s/&/\&/g
adiciona\
também&
na string (linha)
Exemplo:
% text='one&two\&three'
% sed 's/\([^\]\)&/\\&/g' <<< "${text}"
one\&two\&three
% sed -E 's/([^\])&/\\&/g' <<< "${text}"
one\&two\&three
% sed -E 's/[\]+(&)//g; s/&/\&/g' <<<"$text"
one\&two\&three