Como substituir strings contendo barras com sed?


147

Eu tenho um projeto do Visual Studio, desenvolvido localmente. Os arquivos de código precisam ser implantados em um servidor remoto. O único problema é que os URLs contêm códigos codificados.

O projeto contém URLs como ? Page = one . Para que o link seja válido no servidor, ele deve ser / page / one .

Decidi substituir todos os URLS nos meus arquivos de código pelo sed antes da implantação, mas estou preso em barras.

Sei que essa não é uma solução bonita, mas é simples que me pouparia muito tempo. O número total de strings que tenho que substituir é menor que 10. O número total de arquivos que precisam ser verificados é ~ 30.

Exemplo descrevendo minha situação está abaixo:

Comando que estou usando:

sed -f replace.txt < a.txt > b.txt

replace.txt que contém todas as strings:

s/?page=one&/pageone/g
s/?page=two&/pagetwo/g
s/?page=three&/pagethree/g

a.txt:

?page=one&
?page=two&
?page=three&

Conteúdo do b.txt depois de executar o meu comando sed:

pageone
pagetwo
pagethree

O que eu quero que o b.txt contenha:

/page/one
/page/two
/page/three


3
possível duplicata Use barras em sed substituir
tripleee

Respostas:


274

A maneira mais fácil seria usar um delimitador diferente nas linhas de pesquisa / substituição, por exemplo:

s:?page=one&:pageone:g

Você pode usar qualquer caractere como um delimitador que não faça parte de nenhuma das cadeias. Ou você pode escapar com uma barra invertida:

s/\//foo/

O que substituiria /com foo. Você deseja usar a barra invertida de escape nos casos em que não sabe quais caracteres podem ocorrer nas cadeias de substituição (se forem variáveis ​​de shell, por exemplo).


1
> Ou você pode escapar com uma barra invertida. Um exemplo disso seria mais útil, pois nem sempre você sabe quais caracteres estão em uma sequência para poder escolher algo diferente. por exemplo, isto: eco / | sed s / \ // a / g não funciona: expressão sed: -e # 1, caractere 5: opção desconhecida para `s '#
9783 Max Waterman

1
Você poderia adicionar um então? Obrigado :) eu encontrei em torno de aspas duplas parece funcionar: echo / | sed "s / \ / a / g"
Max Waterman

@MaxWaterman, é um procedimento operacional padrão quando sedo comando regex é colocado entre aspas duplas. Não os usei na minha resposta porque não estava mostrando toda a sedlinha de comando, mas apenas a sedcadeia de comando regex como o OP havia feito. Se você o colocar em um arquivo, como o OP fez, não precisará das aspas.
Lurker

Sim, bastante justo (embora talvez possa ser mencionado). Esse exemplo ajuda. Tenho percebido que às vezes preciso colocar muitas barras invertidas ... e isso fica realmente confuso. eg -e "s / '/ \\\\\\\ & / g" Eu acho que o texto está errado, no entanto: "O que substituiria \ por foo" - deveria ser "O que substituiria / com foo", não?
Max Waterman

@ MaxWaterman obrigado por assistir isso em \ vs. /. Corrigido. Se você possui um sedcomando em um script de shell, podem ser necessárias mais barras invertidas (cada barra invertida precisa ser invertida novamente).
Lurker

105

O scomando pode usar qualquer caractere como delimitador; qualquer caractere que vem depois que o sé usado. Fui criado para usar a #. Igual a:

s#?page=one&#/page/one#g

5
A página de manual do BSD sed no OS X diz sobre o comando s : Substitua a sequência de substituição pela primeira instância da expressão regular no espaço do padrão. Qualquer caractere que não seja barra invertida ou nova linha pode ser usado em vez de uma barra para delimitar o RE e a substituição. Eu apostaria que a página de manual do GNU sed diz algo semelhante.
Tom Anderson

A resposta atual aceita é basicamente a mesma que esta e foi postada um minuto antes!
Tom Anderson

61

Um fato muito útil, mas menos conhecido, sobre o sed é que o s/foo/bar/comando familiar pode usar qualquer pontuação, não apenas barras. Uma alternativa comum é s@foo@bar@, a partir da qual se torna óbvio como resolver seu problema.


Aconselhamento genial quando você deseja substituir as barras. Obrigado!
Mbb

9

adicione \ antes de caracteres especiais:

s/\?page=one&/page\/one\//g

etc.


4
Posso ter perdido alguma coisa, mas tentei isso e parece que não funciona. Pareceu a coisa mais óbvia para tentar, mas supondo que eu esteja certo e que realmente não funcione, por que postá-lo?
Codenoob

4
@ codenoob (e qualquer outra pessoa que chegar aqui) - os 's' no início são obrigatórios. s/foo\/bar/foo_bar/vai funcionar, mas /foo\/bar/foo_bar/não vai.
MynockSpit

5

Em um sistema que estou desenvolvendo, a string a ser substituída por sed é um texto de entrada de um usuário que é armazenado em uma variável e passado para sed.

Conforme observado anteriormente nesta postagem, se a sequência contida no bloco de comandos sed contiver o delimitador real usado pelo sed -, o sed será encerrado com erro de sintaxe. Considere o seguinte exemplo:

Isso funciona:

$ VALUE=12345
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345

Isso quebra:

$ VALUE=12345/6
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
sed: -e expression #1, char 21: unknown option to `s'

Substituir o delimitador padrão não é uma solução robusta no meu caso, pois eu não queria limitar o usuário de inserir caracteres específicos usados ​​pelo sed como delimitador (por exemplo, "/").

No entanto, escapar quaisquer ocorrências do delimitador na sequência de entrada resolveria o problema. Considere a solução abaixo de escapar sistematicamente do caractere delimitador na string de entrada antes de analisá-lo por sed. Esse escape pode ser implementado como uma substituição usando o próprio sed, essa substituição é segura mesmo que a cadeia de entrada contenha o delimitador - isso ocorre porque a cadeia de entrada não faz parte do bloco de comando sed:

$ VALUE=$(echo ${VALUE} | sed -e "s#/#\\\/#g")
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345/6

Eu converti isso para uma função a ser usada por vários scripts:

escapeForwardSlashes() {

     # Validate parameters
     if [ -z "$1" ]
     then
             echo -e "Error - no parameter specified!"
             return 1
     fi

     # Perform replacement
     echo ${1} | sed -e "s#/#\\\/#g"
     return 0
}

1
A resposta para mim foi que, se o VALUE que você está usando para substituir DEF_VALUE, possui barras, então você precisa escapar delas com 3 barras invertidas para que o sed funcione, por exemploVALUE="01\\\/01\\\/2018"
alexkb

3

esta linha deve funcionar para seus três exemplos:

sed -r 's#\?(page)=([^&]*)&#/\1/\2#g' a.txt
  • Eu costumava -reconomizar alguns escapamentos.
  • a linha deve ser genérica para o seu um, dois, três casos. você não precisa fazer o sub 3 vezes

teste com seu exemplo (a.txt):

kent$  echo "?page=one&
?page=two&
?page=three&"|sed -r 's#\?(page)=([^&]*)&#/\1/\2#g'
/page/one
/page/two
/page/three


1

Ótima resposta do Anonymous. \ resolvi meu problema quando tentei escapar aspas em strings HTML.

Portanto, se você usar o sed para retornar alguns modelos HTML (em um servidor), use barra invertida dupla em vez de simples:

var htmlTemplate = "<div style=\\"color:green;\\"></div>";

1

sedé o s tream ed itor , em que você pode usar |(pipe) para enviar fluxos padrão (STDIN e STDOUT especificamente) através de sede alterá-los por meio de programação em tempo real, tornando-se uma ferramenta útil na filosofia tradição Unix; mas também pode editar arquivos diretamente, usando o -iparâmetro mencionado abaixo.
Considere o seguinte :

sed -i -e 's/few/asd/g' hello.txt

s/é utilizado para s ubstitute a expressão encontrado fewcom asd:

Os poucos, os corajosos.


O asd, o corajoso.

/gsignifica "global", o que significa fazer isso para toda a linha. Se você deixar de fora /g(com s/few/asd/, sempre precisará haver três barras, não importa o quê) e fewaparecer duas vezes na mesma linha, somente a primeira fewserá alterada para asd:

Os poucos homens, as poucas mulheres, os corajosos.


Os homens asd, as poucas mulheres, os corajosos.

Isso é útil em algumas circunstâncias, como alterar caracteres especiais no início das linhas (por exemplo, substituir os símbolos maiores que algumas pessoas usam para citar o material anterior nos segmentos de email por uma guia horizontal, deixando uma desigualdade algébrica entre aspas mais adiante. intocado), mas no seu exemplo em que você especifica que em qualquer lugar few ocorre, ele deve ser substituído, verifique se possui/g .

As duas opções a seguir (sinalizadores) são combinadas em uma -ie:

-iopção é usada para editar i n lugar no arquivo hello.txt.

-eopção indica o e xpression / comando para executar, neste casos/ .

Nota: É importante que você use -i -epara pesquisar / substituir. Se o fizer -ie, crie um backup de cada arquivo com a letra 'e' anexada.


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.