Se você deseja substituir uma palavra-chave por uma string usando sed, sed tenta muito interpretar sua string de substituição. Se a string de substituição tiver caracteres que o sed considere especiais, como um caractere '/', ela falhará, a menos que você queira que a string de substituição tenha caracteres que digam ao sed como agir.
Ex:
VAR="hi/"
sed "s/KEYWORD/$VAR/g" somefile
Existe alguma maneira de dizer ao sed para não tentar interpretar a sequência de substituição para caracteres especiais? Tudo o que eu quero é poder substituir uma palavra-chave em um arquivo pelo conteúdo de uma variável, independentemente do conteúdo.
bash
shell-script
sed
Tal
fonte
fonte
sed
e fazer com que eles não sejam especiais, basta escapar da barra invertida.VAR='hi\/'
não dá esse problema.sed(1)
apenas interpreta o que recebe. No seu caso, obtém isso através de uma interpolação de shell. Eu acredito que você não pode fazer o que quiser, mas verifique o manual. Eu sei que no Perl (que faz umased
substituição aceitável , com expressões regulares muito mais ricas), você pode especificar que uma string seja literalmente copiada novamente, verifique o manual.Respostas:
Há apenas 4 caracteres especiais na peça de substituição: \, &, nova linha e o delimitador ( ref )
fonte
s///
é uma expressão regular, é realmente apenas uma string (exceto para barras invertidas e escapes ). Se a string de substituição for tão longa, uma linha de shell não é a sua solução.&
Você pode usar Perl em vez de sed com
-p
(assumir loop sobre entrada) e-e
(fornecer programa na linha de comando). Com o Perl, você pode acessar variáveis de ambiente sem interpolá-las no shell. Observe que a variável precisa ser exportada :Se você não deseja exportar a variável para qualquer lugar, forneça-a apenas para esse processo:
Observe que a sintaxe da expressão regular do Perl é, por padrão, ligeiramente diferente da do sed.
fonte
PATTERN
variável de ambiente , não em argumentos. De qualquer forma, esse erro seria oE2BIG
que você obteria igualmente se usassesed
.A solução mais simples que ainda manipularia a grande maioria dos valores de variáveis corretamente seria usar um caractere não imprimível como delimitador do
sed
comando substituto.Em
vi
você pode escapar qualquer caracter de controle digitando Ctrl-V (mais comumente escrito como^V
). Portanto, se você usar algum caractere de controle (eu costumo usar^A
como delimitador nesses casos), seused
comando só será interrompido se esse caractere não imprimível estiver presente na variável em que você está inserindo.Então você digitaria
"s^V^AKEYWORD^V^A$VAR^V^Ag"
e o que receberia (invi
) seria:Isso funcionará desde
$VAR
que não contenha o caractere não imprimível^A
- o que é extremamente improvável.Obviamente, se você está passando a entrada do usuário para o valor de
$VAR
, todas as apostas estão desativadas e é melhor higienizar sua entrada completamente, em vez de depender de caracteres de controle difíceis de digitar para o usuário médio.Na verdade, há muito mais que ter cuidado do que a string delimitadora. Por exemplo,
&
quando presente em uma sequência de substituição, significa "todo o texto correspondente". Por exemplo,s/stu../my&/
substituiria "stuff" por "mystuff", "stung" por "mystung", etc. Portanto, se você tiver algum caractere na variável que está inserindo como uma seqüência de substituição, mas deseja usar o literal valor da variável apenas, você precisará executar alguns serviços de limpeza de dados antes de poder usar a variável como uma sequência de substituiçãosed
. (A limpeza de dados também pode ser feita comsed
.)fonte
sed
oi
comando nsert. Massed
não é uma boa ferramenta para processar grandes quantidades de texto de maneiras complexas. Vou postar outra resposta mostrando como fazer issoawk
.Você pode usar um
,
ou um|
e, em vez disso, será considerado um separador e, tecnicamente, você pode usar qualquer coisana página do manual
Como você pode ver, você deve começar com um \ antes do seu separador no início, e poderá usá-lo como um separador.
da documentação http://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-Command :
Exemplo:
sed -e 'somevar|s|foo|bar|'
echo "Hello all" | sed "s_all_user_"
echo "Hello all" | sed "s,all,user,"
echo "Hello/ World" | sed "s,Hello/,Neo,"
fonte
/
e ele ignorará a/
felicidade, como acabei de apontar .. na verdade, você pode até procurá-la e substituí-la em uma string >>> eu editei com um exemplo >>> esses as coisas não são tão seguras e você sempre encontrará um cara mais espertosed
em primeiro lugar, qual é o seu projeto?bash
é para manipulação de strings. De todo, de todo. É para manipulação de arquivos e coordenação de comandos . Acontece que ele possui algumas funcionalidades úteis para strings, mas são realmente limitadas e não muito rápidas, se essa é a principal coisa que você está fazendo. Consulte "Por que o uso de um loop de shell para processar o texto é considerado uma má prática?" Algumas ferramentas que são projetados para processamento de texto são, em ordem de mais básico ao mais poderoso: , e Perl.sed
awk
Se for baseado em linhas e tiver apenas uma linha para substituir, recomendo anexar o arquivo com a linha de substituição usando
printf
, armazenando a primeira linha nosed
espaço de espera e soltando-a conforme necessário. Dessa forma, você não precisa se preocupar com caracteres especiais. (A única suposição aqui é que$VAR
contém uma única linha de texto sem novas linhas, o que você já disse nos comentários.) Além das novas linhas, o VAR poderia conter qualquer coisa e isso funcionaria independentemente.printf '%s\n'
imprimirá o conteúdo$VAR
como uma string literal, independentemente do seu conteúdo, seguido por uma nova linha. (echo
fará outras coisas em alguns casos, por exemplo, se o conteúdo de$VAR
começar com um hífen - ele será interpretado como um sinalizador de opção que está sendo passado paraecho
.)Os colchetes são usados para anexar a saída
printf
ao conteúdo da formasomefile
como ela é passadased
. O espaço em branco que separa os chavetas por si só é importante aqui, assim como o ponto-e-vírgula antes da chaveta de fechamento.1{h;d;};
como umsed
comando irá armazenar a primeira linha de texto emsed
's espaço de espera , entãod
élete da linha (em vez de imprimi-lo)./KEYWORD/
aplica as seguintes ações a todas as linhas que contêmKEYWORD
. A ação ég
et, que obtém o conteúdo do espaço de espera e o coloca no lugar do espaço do padrão - em outras palavras, a linha atual inteira. (Isso não serve para substituir apenas parte de uma linha.) A propósito, o espaço de espera não é esvaziado, apenas copiado no espaço do padrão, substituindo o que estiver lá.Se você deseja ancorar seu regex para que ele não corresponda a uma linha que contém apenas KEYWORD, mas apenas uma linha onde não há mais nada na linha além de KEYWORD, adicione o início da linha anchor (
^
) e o fim da linha anchor ($
) a seu regex:fonte
Você pode escapar da barra invertida das barras invertidas na sequência de substituição, usando a expansão do parâmetro de substituição de padrão do Bash. É um pouco confuso porque as barras também precisam ser escapadas para o Bash.
resultado
Você pode colocar a expansão do parâmetro diretamente no seu comando sed:
mas acho que a primeira forma é um pouco mais legível. E, é claro, se você vai reutilizar o mesmo padrão de substituição em vários comandos sed, faz sentido fazer a conversão apenas uma vez.
Outra opção seria usar um script escrito em awk, perl ou Python, ou um programa C, para fazer suas substituições em vez de usar sed.
Aqui está um exemplo simples no Python que funciona se a palavra-chave a ser substituída for uma linha completa no arquivo de entrada (sem contar a nova linha). Como você pode ver, é essencialmente o mesmo algoritmo do seu exemplo do Bash, mas lê o arquivo de entrada com mais eficiência.
fonte
\x
seqüências de escape no estilo. Ou para usar um programa que pode lidar com entradas arbitrárias, como mencionei no meu último parágrafo.Foi assim que eu fui:
isso funciona muito bem no meu caso, porque minha palavra-chave está em uma linha por si só. Se a palavra-chave estivesse alinhada com outro texto, isso não funcionaria.
Eu realmente gostaria de saber se existe uma maneira fácil de fazer isso que não envolve codificar minha própria solução.
fonte
echo
nada. Use emprintf
vez disso. E fazer o processamento de texto em um loop de shell é uma má ideia.read
é bastante lento. Destina-se ao processamento de entrada interativa do usuário, não ao processamento de arquivos de texto. É lento porque lê stdin char por char, fazendo uma chamada de sistema para cada char.printf "hi\n"
fará com que printf imprima uma nova linha enquanto aecho "hi\n"
imprime como está.printf
significa "formato" - o primeiro argumento paraprintf
é um especificador de formato . Se esse especificador é%s\n
, que significa "string seguido por nova linha", nada no próximo argumento será interpretado ou traduzido porprintf
em tudo . (O shell ainda pode interpretá-lo, é claro; é melhor colocar tudo entre aspas simples, se for uma string literal, ou aspas duplas, se você desejar expansão variável.) Veja minha resposta usandoprintf
para obter mais detalhes.