Como encontrar e substituir string sem usar o comando Sed?

16

Como todos sabemos, sedé muito eficiente para localizar e substituir cadeia, por exemplo achado 'a' e substituí-lo para 'b': sed 's/a/b/g'.

É possível fazer isso com outro comando ou script de shell em vez de sed?

Isto é para sistemas linux cortados para TV que não possuem o sedcomando. Então eu tenho que usar outros comandos ou scripts em vez desed 's/a/b/g'. –

binghenzq
fonte
Na verdade, isso é apenas substituição baseada em expressão regular. Qualquer ferramenta ou linguagem capaz de lidar com tal coisa será capaz de fazer o mesmo, mas com vários sintaxe: $var=~s/a/b/g, gsub(/a/,"b",var), var.gsub(/a/,'b'), var.replace(/a/g,'b'), preg_replace("/a/","b",$var), regsub -all a b $var. Além disso, muitas ferramentas e idiomas também podem substituir a string de texto sem formatação. Portanto, sua pergunta é de alguma forma ampla.
manatwork
1
Por quê? Que problema você está tentando resolver?
Gilles 'SO- stop be evil'
A sistemas linux cortados para TV não sed comando. Então eu tenho que usar outro comando ou script para em vez de sed 's / a / b / g'.
binghenzq

Respostas:

12

Sim, existem várias maneiras de fazer isso. Você pode usar awk,, perlou bashpara executar essas atividades também. Em geral, porém, sedé provavelmente a ferramenta mais adequada para realizar esses tipos de tarefas.

Exemplos

Digamos que eu tenho esses dados de amostra, em um arquivo data.txt:

foo bar 12,300.50
foo bar 2,300.50
abc xyz 1,22,300.50

awk

$ awk '{gsub("foo", "foofoofoo", $0); print}' data.txt 
foofoofoo bar 12,300.50
foofoofoo bar 2,300.50
abc xyz 1,22,300.50

Perl

$ perl -pe "s/foo/foofoofoo/g" data.txt 
foofoofoo bar 12,300.50
foofoofoo bar 2,300.50
abc xyz 1,22,300.50

Edição embutida

Os exemplos acima também podem modificar diretamente os arquivos. O exemplo Perl é trivial. Basta adicionar a -iopção.

$ perl -pie "s/foo/foofoofoo/g" data.txt 

Pois awké um pouco menos direto, mas igualmente eficaz:

$ { rm data.txt && awk '{gsub("foo", "foofoofoo", $0); print}' > data.txt; } < data.txt

Este método cria um sub-shell com chaves '{...} `, onde o arquivo é redirecionado para ele através deste:

$ { ... } < data.txt

Depois que o arquivo é redirecionado para o sub-shell, ele é excluído e, em seguida, awké executado no conteúdo do arquivo que foi lido nos sub-shells STDIN. Esse conteúdo é então processado awke gravado novamente no mesmo nome de arquivo que acabamos de excluir, substituindo-o efetivamente.

slm
fonte
Obrigado pela resposta e tentarei no próximo dia útil. Mas não tenho certeza se ele funciona porque algum comando talvez não exista em sistemas Linux de TV cortados, como 'sed'. , 'grep' e assim por diante para resolvê-lo.
binghenzq
@binghenzq - adicionei exemplos que editarão inline o arquivo.
slm
Raramente eu voto negativo, mas, neste caso, o ponto da pergunta parecia ser um método mais simples do que outro mais / igualmente complexo e provavelmente também dependente. Se a pergunta fosse sobre alternativas para a instalação completa de uma máquina * nix, provavelmente eu marcaria com +1 essa resposta boa.
Michael Durrant
@ MichaelDurrant - Acabei de adicionar as edições inline elaboradas b / c que o OP solicitou. Além disso, o OP estabeleceu o requisito de NÃO usar sednão eu. Sed é a ferramenta apropriada para fazer substituições como essa, e ele obviamente está pedindo para entender melhor os papéis dessas ferramentas, portanto mostrar a alguém essas coisas, embora seja ruim, é extremamente educativo para mostrar. eles o porquê. Muitas vezes o pessoal que conhece sabe simplesmente diz "não faça" sem explicar o porquê, então eu sou. Mas obrigado por pelo menos deixar um comentário sobre o motivo de você DV.
slm
Claro, eu pensei que era uma ótima resposta em todos os outros aspectos. Sim, eu odeio -1 sem explicação.
Michael Durrant
13

A alternativa clássica para substituições de letra única é o trcomando que deve estar disponível em praticamente qualquer sistema:

$ echo "foobar" | tr a b   
foobbr

tré melhor do que sedpara isso, na verdade, já que usar sed(para não falar em ) perlou awksubstituições de uma letra é como usar uma marreta para matar uma mosca.

grep não foi projetado para isso, não modifica sua entrada, apenas pesquisa através dela.

Como alternativa, você pode usar os recursos de substituição de alguns shells. Aqui usando ksh, zshou bashsintaxe:

$ foo="foobar"
$ echo "${foo//a/b}"
foobbr

Poderíamos fornecer respostas mais específicas se você explicasse exatamente qual problema está tentando resolver.

terdon
fonte
Existe uma opção para ignorar maiúsculas e minúsculas ${foo//a/b}?
AlikElzin-kilaka
@ AlikElzin-kilaka Receio que não. Você terá que usar algo mais sofisticado, como, por exemplo: echo "$foo" | sed 's/a/b/iou dar uma classe de caracteres: echo ${foo//[aA]/b}.
terdon
4

Você pode usar o Vim no modo Ex:

ex -s -c '%s/a/b/g|x' file
  1. % selecione todas as linhas

  2. s substituto

  3. g substituição global

  4. x salvar e fechar

Steven Penny
fonte
muito obrigado. apenas para adicionar, -c flag é executar o comando quando a edição começar (já que ex é um editor) e -s é o modo de script que desativa o feedback ou, como alguns dizem o modo slient. ref para mais informações: ex-vi.sourceforge.net/ex.html
Jimmy MG Lim
3

Se você estiver trabalhando com um arquivo e não com um fluxo, use o editor de texto padrão ed:

printf '%s\n' ',s/a/b/g' w q | ed file.txt

Isso deve estar disponível em qualquer * nix. A vírgula ',s/a/b/g'indica edpara trabalhar em todas as linhas (você também pode usar %, o que será mais familiar se você estiver acostumado a vim), e o restante é uma pesquisa e substituição padrão. wdiz para gravar (salvar) o arquivo, qdiz para sair.

Observe que, ao contrário da -iopção do sed (e opções semelhantes em outras ferramentas), isso realmente edita o arquivo no local, em vez de trapacear com arquivos temporários.

Eu não acho que é possível fazer isso funcionar com fluxos, mas então eu realmente não sei muito sobre ede não ficaria surpreso se ele realmente tiver essa capacidade (a filosofia unix é o que é).

evilsoup
fonte
2

Usando o comando ancestral (no qual -ssignifica silencioso (silencioso) e a vírgula antes dos comandos significa executar em todas as linhas):

Apenas imprimindo em STDOUT :

ed -s file <<!
,s/a/b/g
,p
q
!

substituição no local:

ed -s file <<!
,s/a/b/g
w
q
!
Gilles Quenot
fonte