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 / 744013
Accepted
xpt
xpt
Asked: 2023-04-25 20:51:42 +0800 CST2023-04-25 20:51:42 +0800 CST 2023-04-25 20:51:42 +0800 CST

sed: Substituição bem-sucedida como condição

  • 772

Encontrei um excelente uso de sedpara substituir e usar seu estado bem-sucedido como condição para imprimir a linha:

$ seq 3 | sed -n 's/2/B/ p'
B

Eu estou querendo saber se este formulário curto pode ser estendido para fazer mais ações. Como,

  • imprimir a linha somente se a substituição for bem-sucedida, mas
  • antes de imprimir, preciso fazer mais substituições

Isso seria possível? Eu tentei o seguinte, mas falhei:

$ seq 3 | sed -n 's/2/B/ {p}'
sed: -e expression #1, char 8: unknown option to `s'
sed
  • 4 4 respostas
  • 52 Views

4 respostas

  • Voted
  1. Kusalananda
    2023-04-25T20:57:31+08:002023-04-25T20:57:31+08:00

    Você pode usar /2/como endereço para um comando mais complexo:

    sed -n '/2/ { s/2/B/; /BB/d; p; }'
    

    Isso iria, para qualquer linha contendo pelo menos um 2, substituir a primeira ocorrência de 2por B(nesse caso, essa substituição também poderia ser abreviada para s//B/onde a expressão regular vazia significa "usar a expressão correspondente mais recente") e, em seguida, descartar a linha se ele agora contém a substring BB. Em seguida, a linha seria gerada (se não fosse descartada). Outras linhas não seriam produzidas, devido a -n.

    Você também pode usar

    sed -e '/2/!d' -e 'other commands'
    

    Isso excluiria todas as linhas que não contêm 2e aplicaria other commandsnas linhas restantes.

    Usar várias expressões, cada uma usando -e, é a maneira padrão de aplicar uma série de comandos a um fluxo de entrada com sed. A maioria das implementações atuais sedtambém entende a separação de expressões com ;. GNU sednão precisa ver um ;antes de um arquivo }.

    • 4
  2. Best Answer
    Stéphane Chazelas
    2023-04-25T23:06:06+08:002023-04-25T23:06:06+08:00

    paqui está uma bandeira para o sedcomando, não é o p sedcomando.

    Para fazer algo (além de pimprimir o espaço padrão resultante ou writmá-lo em um arquivo, wsendo outro dos sinalizadores que se pode usar com o scomando) somente se uma substituição foi feita, você pode usar o tcomando (ou o Tcomando no GNU sed) que ramifica para algum rótulo (ou para o final se não houver rótulo) se houver uma substituição (se não houver -T), então você pode fazer:

    GNU específico:

    sed -n 's/2/B/;T;=;p;#and other commands if there were substitutions'
    

    Que é como:

    substitute(the first occurrence of 2 with B in the pattern space)
    if (no substitution was made so far)
       goto(end)
    print-pattern-space
    print-input-line-number
    : end
    
    sed '
      s/2/B/;t more
      d
      :more
      p;=;#and other commands
    '
    

    Ou você pode usar:

    sed -n '/regexp/ { s//replacement/; p; =; }'
    

    Onde usar um regexp vazio reutiliza o anterior como em ed.

    • 3
  3. Ed Morton
    2023-04-25T22:24:52+08:002023-04-25T22:24:52+08:00

    Se você precisar fazer algo diferente, s/old/new/seria melhor usar awk do que sed para alguma combinação de clareza, robustez, portabilidade, facilidade de manutenção, etc.:

    $ seq 3 | awk 'sub(/2/,"B")'
    B
    
    $ seq 3 | awk 'sub(/2/,"B") { sub(/B/,"foo"); print }'
    foo
    
    • 1
  4. bakunin
    2023-04-26T06:31:26+08:002023-04-26T06:31:26+08:00

    Você pode agrupar comandos com "{ .... }". A forma geral é:

    /<regexp>/ {
                 cmd1
                 cmd2
                 ...
               }
    

    "cmd" aqui é qualquer comando sed regular, como "s/.../.../", mas também "p", "q", etc. Pense nisso como uma "regra", aplicável a todos linhas correspondentes ao regexp. Você também pode negar a regra usando um ponto de exclamação entre o regexp e a chave de abertura. Nesse caso, a regra é aplicada a todas as linhas que não correspondem ao regexp.

    Aqui está um exemplo que imprime todas as linhas somente de comentários desde o início de um script até a primeira linha sem comentários:

    sed '/^[[:blank:]]*#/ !{
                              q
                            }'
    

    Todas as linhas que começam com um "#" correspondem à regra e, portanto, são apenas impressas (não usamos a opção "-n" para suprimir isso). A primeira linha (na verdade todas as linhas, mas efetivamente apenas a primeira é processada) que não corresponde ao regexp aciona a regra que simplesmente sai do sed.

    Mas há também outro dispositivo que é ainda mais poderoso do que usar regras: você define os chamados "rótulos". Lugares simbólicos para os quais você ramifica com um comando do tipo GOTO. É assim que funciona:

    1) os scripts sed de ramificação incondicional funcionam assim: a primeira linha de entrada é lida, então todos os comandos sed são aplicados a ela, um após o outro (se a linha for alterada, outros comandos são aplicados a esta linha alterada) até a última comando é alcançado. Se a opção "-n" não for usada, o resultado será impresso em . Só então a próxima linha de entrada é lida e o processo começa de novo, até que a última linha de entrada seja processada.

    Existe uma maneira de alterar a ordem em que os comandos são aplicados à linha atual:

    :

    Este comando não faz nada por si só, mas pode ser usado por outros comandos para ramificar para este local. Você talvez se lembre de linguagens como BASIC e seu comando "goto"? Isso marca um rótulo para o qual um comando "ir para" (como) subsequente pode pular. O comando sed incondicional para ramificar para um rótulo definido anteriormente é

    b

    O "b" significa "ramo". corresponde ao que você definiu com o comando ":". Se você omitir o rótulo, a execução desvia para o final do script.

    Aqui está um exemplo: você obtém um programa, mas infelizmente o recuo do código é feito com caracteres de tabulação em vez de espaços e você deseja alterar isso. Obviamente, você deseja alterar apenas as guias na frente de qualquer código, não as guias dentro do código, pois podem ser necessárias. Infelizmente, não há nenhum dispositivo em expressões regulares para isso diretamente, então você mesmo deve implementá-lo. O algoritmo é: contanto que uma linha esteja no formato espaço em branco, seguida por uma tabulação, altere esta primeira tabulação para 8 espaços em branco e repita na mesma linha até que nenhuma tabulação esteja na frente de qualquer texto. Só então imprima a linha. Essa estrutura semelhante a um loop é configurada usando um comando ":" e um "b". Observe que eu uso \b (em branco) e \t (tab) aqui para tornar os diferentes tipos de espaço em branco legíveis.

    sed ':start
         /^\b*\t/ {
                    s/^\(\b*\)\t/\1\b\b\b\b\b\b\b\b/
                    b start
                  }'
    

    2) ramificação condicional Agora que você sabe como configurar rótulos e ramificar para eles, há uma reviravolta ainda maior: você pode ramificar para tal rótulo dependendo de um comando s/.../.../ executado antes de ser bem-sucedido (ou seja: mudou alguma coisa) ou não. Os comandos para fazer isso são:

    t

    que desvia para se um dos s/../../-comandos fez uma substituição bem-sucedida desde que a última linha foi lida OU desde a última execução do comando at ou T e

    T

    que é a contraparte negada de "t". Ele ramifica se nenhum comando s foi bem-sucedido.

    Aqui está um exemplo simples de como isso funciona. Não faz nada particularmente útil, mas mostra o princípio: o sed-script leva apenas a primeira linha de qualquer entrada. Se o primeiro caractere for "a", "b" ou "c", imprime "SIM", caso contrário, "NÃO".

    sed -n 's/^[abc]/x/
            t yes
            b no
            :no
            s/^.*$/NO/p
            q
            :yes
            s/^.*$/YES/p
            q'
    

    O fluxo de controle é simples: primeiro tenta-se uma substituição onde o primeiro caractere é trocado por um "x" se for "a", "b" ou "c". Caso seja bem-sucedido, o comando de ramificação "t yes" irá ramificar para o lael "yes", onde toda a linha é alterada para "YES" e sed sai (o comando "q"). Se esta substituição não for bem-sucedida, o comando "t" é passado e o comando "b" é executado, saltando para o rótulo "não".

    Experimente várias entradas ( echo "..." | sed <script>é bom o suficiente) para ver como funciona, depois mude o comando "t" para um "T" e observe o efeito nos resultados.

    • 1

relate perguntas

  • Linux grep o que no arquivo 1 está no arquivo 2 [duplicado]

  • como grep linhas após a terceira vírgula com condição

  • remova o número de linhas duplicadas com base na correspondência antes da primeira vírgula

  • Como posso melhorar este script de conversão de personagens?

  • Como remover uma única linha entre duas linhas

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