Pergunta

Na minha script bash Eu tenho um link externo (recebido do usuário) string, que eu deveria usar no padrão sed.

REPLACE="<funny characters here>"
sed "s/KEYWORD/$REPLACE/g"

Como posso escapar a corda $REPLACE por isso seria aceito com segurança por sed como uma substituição literal?

NOTA:. O KEYWORD é uma substring mudo sem partidas etc. Não é fornecido pelo usuário

Foi útil?

Solução

Aviso : Isso faz não considerar novas linhas. Para uma resposta mais aprofundada, veja este SO-pergunta . (Obrigado, Ed Morton & Niklas Peter)

Note que escapar tudo é uma má idéia. necessidades SED muitos personagens para ser escapado para get seu significado especial. Por exemplo, se você escapar de um dígito no texto de substituição, ele vai se transformar em uma referência anterior.

Como Ben Blank disse, existem apenas três caracteres que precisam ser escapados na string de substituição (escapa-se, de barra de final de declaração e & para substituir todos):

sed -e 's/[\/&]/\\&/g'

Se você precisar de escapar a corda KEYWORD, o seguinte é o que você precisa:

sed -e 's/[]\/$*.^[]/\\&/g'

Lembre-se, se você usar um caractere diferente de / como delimitador, você precisa substituir a barra nas expressões acima wih o personagem que você está usando. Veja o comentário de PeterJCLaw para explicação.

Editado: Devido a alguns casos de canto anteriormente não contabilizados, os comandos acima mudaram diversas vezes. Verifique o histórico de edição para mais detalhes.

Outras dicas

O comando sed permite que você use outros personagens em vez de / como separador:

sed 's#"http://www\.fubar\.com"#URL_FUBAR#g'

As aspas não são um problema.

As únicas três caracteres literais, que são tratados especificamente na cláusula substituir são / (para fechar a cláusula), \ (escapar caracteres, referência anterior, e c.), E & (para incluir o jogo na substituição). Portanto, tudo o que você precisa fazer é escapar esses três personagens:

sed "s/KEYWORD/$(echo $REPLACE | sed -e 's/\\/\\\\/g; s/\//\\\//g; s/&/\\\&/g')/g"

Exemplo:

$ export REPLACE="'\"|\\/><&!"
$ echo fooKEYWORDbar | sed "s/KEYWORD/$(echo $REPLACE | sed -e 's/\\/\\\\/g; s/\//\\\//g; s/&/\\\&/g')/g"
foo'"|\/><&!bar

Com base em expressões regulares de Pianosaurus, fiz uma função bash que escapa tanto de palavras-chave e substituição.

function sedeasy {
  sed -i "s/$(echo $1 | sed -e 's/\([[\/.*]\|\]\)/\\&/g')/$(echo $2 | sed -e 's/[\/&]/\\&/g')/g" $3
}

Aqui está como você usá-lo:

sedeasy "include /etc/nginx/conf.d/*" "include /apps/*/conf/nginx.conf" /etc/nginx/nginx.conf

É um pouco tarde para responder ... Mas há uma maneira muito mais simples de fazer isso. Basta alterar o delimitador (ou seja, o caráter que os campos separa). Assim, em vez de s/foo/bar/ você escreve s|bar|foo.

E, aqui é a maneira fácil de fazer isso:

sed 's|/\*!50017 DEFINER=`snafu`@`localhost`\*/||g'

A saída resultante é desprovido dessa cláusula DEFINER desagradável.

Acontece que você está fazendo a pergunta errada. Eu também fez a pergunta errada. A razão que é errado é o início da primeira frase: "Na minha o bash script ..."

Eu tive a mesma pergunta e cometeu o mesmo erro. Se você estiver usando bash, você não precisa usar sed para fazer substituições de corda (e é muito mais limpo para usar o recurso de substituir construído em bash).

Em vez de algo como, por exemplo:

function escape-all-funny-characters() { UNKNOWN_CODE_THAT_ANSWERS_THE_QUESTION_YOU_ASKED; }
INPUT='some long string with KEYWORD that need replacing KEYWORD.'
A="$(escape-all-funny-characters 'KEYWORD')"
B="$(escape-all-funny-characters '<funny characters here>')"
OUTPUT="$(sed "s/$A/$B/g" <<<"$INPUT")"

Você pode usar o bash apresenta exclusivamente:

INPUT='some long string with KEYWORD that need replacing KEYWORD.'
A='KEYWORD'
B='<funny characters here>'
OUTPUT="${INPUT//"$A"/"$B"}"

Use awk - é mais limpo:

$ awk -v R='//addr:\\file' '{ sub("THIS", R, $0); print $0 }' <<< "http://file:\_THIS_/path/to/a/file\\is\\\a\\ nightmare"
http://file:\_//addr:\file_/path/to/a/file\\is\\\a\\ nightmare

Aqui está um exemplo de um AWK eu usei um tempo atrás. É um AWK que imprime novas Awks. AWK e SED sendo semelhante pode ser um modelo bom.

ls | awk '{ print "awk " "'"'"'"  " {print $1,$2,$3} " "'"'"'"  " " $1 ".old_ext > " $1 ".new_ext"  }' > for_the_birds

Parece excessivo, mas de alguma forma, essa combinação de citações trabalha para manter o "impresso como literais. Em seguida, se bem me lembro os vaiables estão apenas cercado com citações como esta: "$ 1". Experimente, deixe-me saber como ele funciona com SED.

Eu tenho uma melhoria em relação a função sedeasy, que irá romper com caracteres especiais como guia.

function sedeasy_improved {
    sed -i "s/$(
        echo "$1" | sed -e 's/\([[\/.*]\|\]\)/\\&/g' 
            | sed -e 's:\t:\\t:g'
    )/$(
        echo "$2" | sed -e 's/[\/&]/\\&/g' 
            | sed -e 's:\t:\\t:g'
    )/g" "$3"
}

Então, o que é diferente? $1 e $2 entre aspas para evitar expansões shell e preservar guias ou espaços duplos.

| sed -e 's:\t:\\t:g' adicionais tubulação (I como : como token) que transforma uma guia no \t.

não se esqueça todo o prazer que ocorrer com o shell limitação ao redor "e '

modo (em ksh)

Var=">New version of \"content' here <"
printf "%s" "${Var}" | sed "s/[&\/\\\\*\\"']/\\&/g' | read -r EscVar

echo "Here is your \"text\" to change" | sed "s/text/${EscVar}/g"

Se o caso passa a ser que você está gerando uma senha aleatória para passar para sed substituir padrão, então você optar por ter cuidado sobre qual conjunto de caracteres na seqüência aleatória. Se você escolher uma senha feita através da codificação de um valor como base 64, então não há é único personagem que é possível em base64 e também é um caractere especial no sed substituir padrão. Esse personagem é "/", e é facilmente removido da senha que você está gerando:

# password 32 characters log, minus any copies of the "/" character.
pass=`openssl rand -base64 32 | sed -e 's/\///g'`;

Se você está apenas olhando para substituir valor da variável no comando sed, em seguida, basta remover Exemplo:

sed -i 's/dev-/dev-$ENV/g' test to sed -i s/dev-/dev-$ENV/g test

Uma maneira mais fácil de fazer isso é simplesmente construir a cadeia antes de mão e usá-lo como um parâmetro para sed

rpstring="s/KEYWORD/$REPLACE/g"
sed -i $rpstring  test.txt
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top