AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 701591
Accepted
Ahmed Moselhi
Ahmed Moselhi
Asked: 2022-05-06 19:13:19 +0800 CST2022-05-06 19:13:19 +0800 CST 2022-05-06 19:13:19 +0800 CST

encontre uma string em cada linha de um arquivo e substitua outra string na mesma linha usando o bash

  • 772

aqui está meu roteiro:

#! /bin/bash

# C-band Edit
dqt='"'
str5="polarization=${dqt}2${dqt}"
for x in {3600..4200} do;
    sed -i "/$str5.*$x/s/$x/$((x-600))/" satellites.xml
done

tudo o que quero fazer é substituir o número x por x-600 entre 3600 e 4200 em todas as linhas que têm str5 em satellites.xml, mas o script acima me dá erro de sintaxe

linux bash
  • 2 2 respostas
  • 48 Views

2 respostas

  • Voted
  1. Best Answer
    cas
    2022-05-06T20:00:12+08:002022-05-06T20:00:12+08:00

    Apenas me ocorreu que você não quis dizer a string literal x-600, você quis dizer "subtrair 600 de cada valor encontrado entre 3600 e 4200". Nesse caso, use perl, não sed:

    echo "$str5. foo bar 3200 3964 4155 4200 4255" |
      perl -p -e "if (/$str5/) {s/3[6789]\d\d|4[01]\d\d|4200/$&-600/eg}"
    polarization="2". foo bar 3200 3364 3555 3600 4255
    

    Isso usa o /emodificador regex do perl para fazer com que o lado direito ( $&-600) seja avaliado como uma expressão perl . $&é uma variável perl que contém o valor da correspondência, então $&-600significa subtrair 600 desse valor.

    Vou deixar minha resposta original abaixo caso fosse isso que você realmente queria. Também porque tem explicações úteis que ainda são um pouco relevantes para a resposta perl acima.

    Assim como o sed, o perl tem uma -iopção para edição no local para que você possa aplicá-la diretamente ao seu arquivo satellites.xml. Veja man perlrunpara detalhes.

    perl -i -p -e "if (/$str5/) {s/3[6789]\d\d|4[01]\d\d|4200/$&-600/eg}" satellites.xml
    

    Também digno de nota: Você provavelmente deve usar um analisador XML quando estiver trabalhando com arquivos XML. Felizmente, o perl tem vários para escolher, por exemplo, XML::Parser ou a coleção libxml-perl .


    Não tenho uma amostra de sua entrada real, então criei uma que demonstrará o que será alterado e o que não será:

    str5='polarization="2"'
    
    echo "$str5. foo bar 3500 3964 4155 4200 4255" | 
      sed -e "/$str5/ {s/3[6-9][0-9][0-9]/3-600/g; s/4[01][0-9][0-9]/4-600/g; s/4200/4-600/g}"
    polarization="2". foo bar 3500 3-600 4-600 4-600 4255
    

    Traduzido aproximadamente para o inglês, isso é "se a linha atual contiver $str5 ( polarization="2"), aplique essas três s///operações a ela".

    Notas:

    • Não há necessidade de fazer um loop de 3600..4200. Isso fará todas as alterações em uma execução de sed, não em 600 execuções.

    • Você queria que os valores de 3600-4200 fossem alterados. Isso significa que você precisa de 3 operações de pesquisa e substituição:

      • um para 3600-3999
      • um para 4000-4199
      • um por exatamente 4200
    • Alternativamente, isso pode ser feito com duas s///operações, combinando as duas últimas em uma:

        sed -e "/$str5/ { s/3[6-9][0-9][0-9]/3-600/g; s/4[01][0-9][0-9]\|4200/4-600/g }"
      
    • Provavelmente existem muitas outras maneiras de otimizar os regexes, mas quanto mais você fizer isso, mais difícil será ler e modificar no futuro.

    • 3964, 4155, e 4200foram alterados. 3500e 4255não foram, eles ficam fora do intervalo desejado.

    • [0-9]não funcionará como esperado em algumas localidades (onde houver outros caracteres nesse intervalo). Não sei exatamente quais localidades, mas já vi isso mencionado com frequência suficiente para saber que [0-9]não pode ser totalmente confiável. Se isso afetar você, você pode usar [[:digit:]]em vez de [0-9], ou usar perl -pem vez de sed(assim você pode usar \dem vez de [0-9]). O mesmo se aplica ao intervalo [6-9], use [6789]em vez disso.

    • Por fim, tenha muito cuidado com o que você coloca na $str5variável. Por estar sendo interpolado em um sedcomando, será muito fácil quebrar o script sed (por exemplo, se $str5contiver um /, ele quebrará a /$str5/correspondência). O sed não sabe que seu script veio parcialmente de uma variável do shell, tudo o que ele vê é o script que foi dado para executar.

      Além disso, a string inteira será interpretada por sed como uma expressão regular - isso significa que os metacaracteres regex não serão interpretados como caracteres literais, a menos que sejam escapados com um \. por exemplo ., será interpretado como "qualquer caractere" em vez de um ponto literal, a menos que seja escapado como\.

    • 2
  2. Philippos
    2022-05-07T00:59:04+08:002022-05-07T00:59:04+08:00

    Sua tentativa está correta em princípio, você acabou de fechar a lista antes do docom ponto e vírgula, como frabjous apontou:

    for x in {3600..4200}; do
    

    Mas observe que isso fará com que você edite o arquivo 601 vezes "no local", criando e excluindo centenas de novos arquivos cada vez que você executar isso.

    Para evitar isso você pode

    1. Ensine sedum pouco de compreensão básica de números para fazer isso de uma só vez, o que é divertido, mas não é realmente útil
    2. Use uma ferramenta que possa calcular números como python, perlouawk
    3. Reduza para apenas sete substituições reais nas quais você pode alimentar sed:
        #! /bin/bash
        # C-band Edit
        dqt='"'
        str5="polarization=${dqt}2${dqt}"
        sed -Ei "/$str5$x/{"$(for x in {36..41}; do echo -n "s/$x([0-9]{2})/$((x-6))\\1/;"; done)";s/4200/3600/;}" satellites.xml
    

    A substituição produzirá o sedscript

    s/36([0-9]{2})/30\1/;s/37([0-9]{2})/31\1/;s/38([0-9]{2})/32\1/;s/39([0-9]{2})/33\1/;s/40([0-9]{2})/34\1/;s/41([0-9]{2})/35\1/;s/4200/3600/
    
    • 1

relate perguntas

  • Problema estranho ao passar variáveis ​​do arquivo de texto

  • Enquanto a linha lê mantendo os espaços de escape?

  • ordem de substituição de processos `te` e `bash`

  • Passe o sistema de arquivos raiz por rótulo para o kernel do Linux

  • Execute um script muito lento até que seja bem-sucedido

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve