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 / 776271
Accepted
dhm
dhm
Asked: 2024-05-11 18:16:48 +0800 CST2024-05-11 18:16:48 +0800 CST 2024-05-11 18:16:48 +0800 CST

como substituir as últimas n ocorrências de string usando sed

  • 772

Posso substituir a terceira ocorrência de uma string por:

sed 's/OLD/NEW/3'

ou, com a implementação GNU de sed, todas as ocorrências começando na terceira com:

sed 's/OLD/NEW/3g'

Mas como faço para substituir as últimas 3 (ou n) ocorrências?

bash
  • 4 4 respostas
  • 191 Views

4 respostas

  • Voted
  1. Kusalananda
    2024-05-11T18:33:35+08:002024-05-11T18:33:35+08:00

    A maneira mais simples de alterar as três últimas instâncias de uma string que corresponde a um padrão específico é reverter cada linha de entrada e substituir a string invertida:

    $ echo 'this OLD is OLD OLD OLD!' | rev | sed -e 's/DLO/WEN/' -e 's/DLO/WEN/' -e 's/DLO/WEN/' | rev
    this OLD is NEW NEW NEW!
    

    Pode haver maneiras melhores de fazer isso se o formato específico das linhas relevantes for conhecido. Por exemplo, na string de teste que uso acima, poderíamos simplesmente ter substituído OLD OLD OLDpor NEW NEW NEW.

    Observe também que, como as expressões regulares são aplicadas da esquerda para a direita, a substituição da string invertida pode exigir um padrão diferente da reversão ingênua da expressão original. Como exemplo, considere que a substituição das duas primeiras letras em abab, quando invertida, deve substituir as duas últimas letras em baba.


    A inversão de uma linha pode ser feita sedassim, usando @como um caractere pivô para dividir a string em uma parte não invertida e uma parte invertida:

    :loop
    s/^\([^@]\)\([^@]*\)@\{0,1\}\(.*\)/\2@\1\3/
    t loop
    s/@//
    
    • 4
  2. Stéphane Chazelas
    2024-05-11T22:10:47+08:002024-05-11T22:10:47+08:00

    Uma abordagem poderia ser:

    sed '
      # replace *all* OLDs with newline:
      s/OLD/\
    /g
      :1
        # replace one newline back to a OLD as long as it is
        # followed by at least 3 newlines, relying on the fact
        # that the first .* will match greedily as much as possible.
        s/\(.*\)\n\(.*\n.*\n.*\n\)/\1OLD\2/
    
        # repeat as long as the above was successful:
      t1
      # replace the remaining newlines with NEW:
      s/\n/NEW/g'
    

    Com perl, fazendo a substituição duas vezes, uma vez e sem alteração para registrar o número de ocorrências, e uma segunda vez para substituir apenas a (n-2)-ésima pela n- ésima ocorrência:

    perl -pe '$n = s/OLD/$&/g; s/OLD/--$n < 3 ? "NEW" : $&/ge'
    

    Para strings arbitrárias e número máximo de ocorrências:

    perl -spe '$n = s/\Q$old\E/$&/g;
               s/\Q$old\E/--$n < $max ? $new : $&/ge
              ' -- -old=OLD -new=NEW -max=3
    

    s/OLD/$&/gsubstitui todas as ocorrências por si mesmas ( $&contém o que foi correspondido como sed's &) e retorna o número de substituições. Alternativamente, você pode usar s/OLD\K//gwhich substitui o Nothing After OLDpor Nothing , \Ksendo usado para marcar o início do que está sendo substituído.

    • 2
  3. Ed Morton
    2024-05-13T21:16:55+08:002024-05-13T21:16:55+08:00

    Usando GNU awk para patsplit():

    $ echo 'OLDOLDOLDOLDOLD' |
        awk '
            {
                nf = patsplit($0,f,"OLD",s)
                out = s[0]
                for ( i=1; i<=nf; i++ ) {
                    out = out ( i>(nf-3) ? "NEW" : f[i] ) s[i]
                }
                print out
            }
        '
    OLDOLDNEWNEWNEW
    

    Você pode fazer o mesmo em qualquer awk com um loop while (match())ou while(index())e substr()s, é apenas um pouco mais de código para escrever. O acima trata OLDcomo um regexp, se não é isso que você deseja, use um while(index())loop ou escreva código para escapar de qualquer metachars OLDque possa conter, por exemplo, em qualquer awk usando strings literais:

    echo 'OLDOLDOLDOLDOLD' |
        awk -v old="OLD" -v new="NEW" -v cnt=3 '
            {
                nf = strsplit($0,f,old,s)
                out = s[0]
                for ( i=1; i<=nf; i++ ) {
                    out = out ( i>(nf-cnt) ? "NEW" : f[i] ) s[i]
                }
                print out
            }
    
            function strsplit(str,flds,tgt,seps,    pos,cnt,lgth)    {
                lgth = length(tgt)
                while ( pos = index(str,tgt) ) {
                    seps[cnt++] = substr(str,1,pos-1)
                    flds[cnt]   = substr(str,pos,lgth)
                    str         = substr(str,pos+lgth)
                }
                seps[cnt] = str
                return cnt+0
            }
        '
    OLDOLDNEWNEWNEW
    
    • 1
  4. Best Answer
    user9101329
    2024-05-15T15:31:33+08:002024-05-15T15:31:33+08:00

    Embora não exista uma opção sed direta para esta operação, aqui está uma abordagem prática: substitua a última ocorrência da string por:

    $ sed -E 's/(.*)OLD/\1NEW/' input_file
    

    Como n geralmente é pequeno, você pode simplesmente canalizar isso para o mesmo comando n vezes:

    $ sed -E 's/(.*)OLD/\1NEW/' input_file | sed -E 's/(.*)OLD/\1NEW/' | sed -E 's/(.*)OLD/\1NEW/'
    

    ou mais simplesmente repita este comando n vezes:

    $ sed -Ei 's/(.*)OLD/\1NEW/' input_file
    

    (observe que neste caso o input_file muda)

    • 1

relate perguntas

  • exportar variáveis ​​​​env programaticamente, via stdout do comando [duplicado]

  • 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`

  • 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