Como escapar de caracteres não escapados com sed?

2

Eu gostaria de usar sed para escapar de todas as ocorrências não escapadas de um caractere, digamos "& amp;", em uma string contida na variável text . O que eu faço é

text='one&two\&three'
sed 's/\([^\]\)&/\&/g' <<< "${text}"

e espero que a saída seja one\&two\&three . No entanto, o que obtenho é

one\e&two\&three

O que eu faço (tente):

  • o padrão de pesquisa \([^\]\)& deve corresponder a qualquer ocorrência de & não precedida por uma barra invertida e armazenar o caractere que precede & em
  • o padrão de substituição \& deve colocar uma barra invertida entre & e o caractere anterior, mas ele age como \& por algum motivo estranho

O que estou fazendo de errado aqui?

    
por AndreasT 14.10.2016 / 18:51

1 resposta

4

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, para one&two\&three , isso corresponderá a e antes do primeiro & , coloque isso no grupo capturado 1. Para o & antes de three , isso não será correspondido, pois \ é antes de &

  • Na substituição você usou \& , então a saída se torna one\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 por e\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
    
por heemayl 14.10.2016 / 18:56