Substituição no arquivo de texto ** sem ** expressões regulares

55

Eu preciso substituir algum texto dentro de um arquivo de texto por um substituto. Normalmente eu faria algo como

sed -i 's/text/replacement/g' path/to/the/file

O problema é que ambos text e replacement são strings complexas contendo traços, barras, barras pretas, aspas e assim por diante. Se eu escapar de todos os caracteres necessários dentro de text , a coisa se torna rapidamente ilegível. Por outro lado, não preciso do poder das expressões regulares: basta substituir o texto literalmente.

Is there a way to do text substitution without using regular expressions with some bash command?

Seria bastante trivial escrever um script que faça isso, mas imagino que já exista algo.

    
por Andrea 09.05.2012 / 17:00

9 respostas

4

Quando você não precisa do poder das expressões regulares, não o use. Tudo bem.
Mas isso não é realmente uma expressão regular .

sed 's|literal_pattern|replacement_string|g'

Então, se / é problema seu, use | e você não precisa escapar do primeiro.

ps: sobre os comentários, veja também esta resposta do Stackoverflow em Escape de uma string para o padrão de pesquisa sed .

Atualização: se você está bem usando o Perl , tente com \Q e \E como este, e perl -pe 's|\Qliteral_pattern\E|replacement_string|g'
RedGrittyBrick também sugeriu um truque similar com uma sintaxe Perl mais strong em um comentário aqui

    
por 09.05.2012 / 17:10
10
export FIND='find this'
export REPLACE='replace with this'
ruby -p -i -e "gsub(ENV['FIND'], ENV['REPLACE'])" path/to/file

Esta é a única solução 100% segura aqui, porque:

  • É uma subestição estática, não é um regexp, não é necessário escapar de nada (portanto, superior ao uso de sed )
  • Ele não será quebrado se sua string contiver } char (portanto, superior a uma solução Perl enviada)
  • Ele não quebrará com nenhum caractere, porque ENV['FIND'] é usado, não $FIND . Com $FIND ou seu texto embutido no código Ruby, você pode encontrar um erro de sintaxe se sua string contiver um ' sem escape.
por 25.08.2014 / 03:15
7

O comando replace fará isso.

link

Alterar no lugar:

replace text replacement -- path/to/the/file

Para a stdout:

replace text replacement < path/to/the/file

Exemplo:

$ replace '.*' '[^a-z ]{1,3}' <<EOF
> r1: /.*/g
> r2: /.*/gi
> EOF
r1: /[^a-z ]{1,3}/g
r2: /[^a-z ]{1,3}/gi

O comando replace vem com o MySQL ou o MariaDB.

    
por 22.01.2017 / 22:57
3

Você também pode usar o mecanismo \Q do perl para " metacaracteres de padrão quote (disable) "

perl -pe 'BEGIN {$text = q{your */text/?goes"here"}} s/\Q$text\E/replacement/g'
    
por 09.05.2012 / 17:25
2

confira meu script em Perl. faz exatamente o que você precisa sem uso implícito ou explícito de expressão regular:

link

str_replace Search Replace File # replace in File in place

STDIN | str_replace Search Replace # to STDOUT

muito acessível, certo? Eu tive que aprender Perl para fazer isso. porque eu realmente preciso disso.

    
por 04.07.2015 / 19:45
2

Você pode fazer isso escapando dos seus padrões. Assim:

keyword_raw='1/2/3'
keyword_regexp="$(printf '%s' "$keyword_raw" | sed -e 's/[]\/$*.^|[]/\&/g')"
# keyword_regexp is now '1\/2\/3'

replacement_raw='2/3/4'
replacement_regexp="$(printf '%s' "$replacement_raw" | sed -e 's/[\/&]/\&/g')"
# replacement_regexp is now '2\/3\/4'

echo 'a/b/c/1/2/3/d/e/f' | sed -e "s/$keyword_regexp/$replacement_regexp/"
# the last command will print 'a/b/c/2/3/4/d/e/f'

Créditos para esta solução estão disponíveis aqui: link

Nota 1: isto só funciona para palavras-chave não vazias. Palavras-chave vazias não são aceitas por sed ( sed -e 's//replacement/' ).

Nota 2: infelizmente, eu não conheço uma ferramenta popular que NÃO usaria regexp-s para resolver o problema. Você pode escrever tal ferramenta em Rust ou C, mas não está lá por padrão.

    
por 21.04.2016 / 10:53
1

Eu reuni algumas outras respostas e descobri isso:

function unregex {
   # This is a function because dealing with quotes is a pain.
   # http://stackoverflow.com/a/2705678/120999
   sed -e 's/[]\/()$*.^|[]/\&/g' <<< "$1"
}
function fsed {
   local find=$(unregex "$1")
   local replace=$(unregex "$2")
   shift 2
   # sed -i is only supported in GNU sed.
   #sed -i "s/$find/$replace/g" "$@"
   perl -p -i -e "s/$find/$replace/g" "$@"
}
    
por 11.05.2013 / 22:22
1

Você pode usar o str_replace do php:

php -R 'echo str_replace("\|!£$%&/()=?^\"'\''","replace",$argn),PHP_EOL;'<input.txt >output.txt

Observação: você ainda precisará evitar as aspas simples ' e as aspas duplas " .

    
por 31.07.2017 / 13:12
0

Equivalente a Node.JS de @Nowaker:

export FNAME='moo.txt'
export FIND='search'
export REPLACE='rpl'
node -e 'fs=require("fs");fs.readFile(process.env.FNAME,"utf8",(err,data)=>{if(err!=null)throw err;fs.writeFile(process.env.FNAME,data.replace(process.env.FIND,process.env.REPLACE),"utf8",e=>{if(e!=null)throw e;});});'
    
por 09.07.2018 / 06:01