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 / 741068
Accepted
Tim50001
Tim50001
Asked: 2023-03-27 15:54:49 +0800 CST2023-03-27 15:54:49 +0800 CST 2023-03-27 15:54:49 +0800 CST

Como você obtém as saídas individuais do grep?

  • 772

Eu vi grep jogado em muitas respostas, mas nunca pensei nisso.

Agora que estou tentando obter o conteúdo dentro de tags HTML de uma página salva localmente da Internet, bati em uma parede. Posso obter o grep para identificar a saída que desejo, mas sem a menor chance de delimitá-la para ser utilizável.

Este é o conteúdo do meu arquivo test.sh:

a=$(awk '/<div class="power-bar-text">/,/<\/div>/' 'Acid Fast.html')
b=$(echo $a | grep -PzTo [0-9\.]+)
echo $a
echo $b

Resultados nesta saída do terminal:

test.sh: line 4: warning: command substitution: ignored null byte in input
<div class="power-bar-text"> 9 </div> <div class="power-bar-text"> 8 </div> <div class="power-bar-text"> 11.25 </div> <div class="power-bar-text"> 10 </div> <div class="power-bar-text"> 6 </div> <div class="power-bar-text"> 5 </div> <div class="power-bar-text"> 2 (1s) </div> <div class="power-bar-text"> 3 </div> <div class="power-bar-text"> 2.50 </div>
9811.2510652132.50

Aqui está uma iteração anterior que tinha uma legibilidade humana um pouco melhor:

$ awk '/<div class="power-bar-text">/,/<\/div>/' 'Acid Fast.html' | grep -Pzn -C1 [0-9\.]+ -
1:            <div class="power-bar-text">
                9
            </div>
            <div class="power-bar-text">
                8
            </div>
            <div class="power-bar-text">
                11.25
            </div>
            <div class="power-bar-text">
                10
            </div>
            <div class="power-bar-text">
                6
            </div>
            <div class="power-bar-text">
                5
            </div>
            <div class="power-bar-text">
                2 (1s)
            </div>
            <div class="power-bar-text">
                3
            </div>
            <div class="power-bar-text">
                2.50
            </div>

Não sei como configurar a coloração na caixa de código acima, mas o terminal a codifica com a cor de fonte correspondente padrão vermelha para cada dígito e ponto ali.

(Isso provavelmente não funcionaria se os nomes das classes fossem "power.bar.text" porque o ponto corresponderia lá... Portanto, alguma ajuda para garantir que qualquer ponto seja um dígito? Acho que poderia ser para o regex [0-9]+\.?[0-9]*. )

Mas voltando ao primeiro bloco de código usando o código do bash, a saída final que ele fornece é 9811.2510652132.50. Mas eu quero algo como9,8,11.25,10,6,5,2,1,3,2.50

Se eu tivesse codificado o grep, teria a -d,opção de configurar o delimitador como um comando na saída. Infelizmente, essa ideia não funcionou quando tentei.

Uma péssima ideia que tive e que pode funcionar é usar a saída do parâmetro -m para processá-la repetidamente, incrementando o número de correspondências permitidas e, em seguida, descobrir o que há de novo entre cada saída. Mais uma vez, isso soa terrível. (Por exemplo, eu espero que -m1 me dê 9, então -m2 me daria 98, e -m3 me daria 9811,25 e eu "subtrairia" a saída de m2 da saída de m1 para ser o 8; a saída de m3 da saída de m2 para obter o 11.25.)

E, na verdade, tendo acabado de tentar isso, NÃO funciona porque acho que o awk torna uma única linha, portanto, não importa quantas correspondências eu limite, a string completa de é gerada, porque a totalidade 9811.2510652132.50dela é a primeira e única correspondência.

Certamente há uma maneira melhor?

awk
  • 2 2 respostas
  • 497 Views

2 respostas

  • Voted
  1. Best Answer
    Kusalananda
    2023-03-27T16:28:40+08:002023-03-27T16:28:40+08:00

    Conforme mencionado nos comentários , grep(um utilitário para extrair linhas de documentos de texto não estruturados) não é uma ferramenta que você deseja usar para analisar HTML ou documentos estruturados em geral. Idealmente, você deseja usar uma ferramenta capaz de aplicar consultas estruturadas no documento para extrair, modificar ou processar os dados de outras maneiras. Para documentos XML, uma dessas ferramentas de linha de comando é xmlstarlet, com a qual você pode aplicar consultas XPath a documentos XML.

    Supondo que seu documento HTML seja XHTML adequado, podemos extrair o conteúdo dos divnós que possuem classatributos com o valor power-bar-text, enquanto ao mesmo tempo aparamos os espaços em branco flanqueadores:

    xmlstarlet select --template \
        --match '//div[@class="power-bar-text"]' \
        --value-of 'normalize-space()' -nl file.xml
    

    Isso primeiro corresponde aos divnós nos quais estamos interessados ​​e, em seguida, extrai o resultado da normalize-space()função aplicada a esses nós correspondentes. No final, -nldelimita cada saída com um caractere de nova linha.

    Ou, usando opções curtas,

    xmlstarlet sel -t \
        -m '//div[@class="power-bar-text"]' \
        -v 'normalize-space()' -n file.xml
    

    Dado o fragmento de documento que você mostra, isso provavelmente resultaria em algo como o seguinte:

    9
    8
    11.25
    10
    6
    5
    2 (1s)
    3
    2.50
    

    Isso pode ser colocado em uma única linha com vírgulas como delimitadores, passando-o por

    paste -d , -s -
    

    ... igual a:

    $ xmlstarlet sel -t -m '//div[@class="power-bar-text"]' -v 'normalize-space()' -n file.xml | paste -d , -s -
    9,8,11.25,10,6,5,2 (1s),3,2.50
    

    Adicione algum processamento extra se desejar apenas o que ocorrer antes do primeiro espaço em cada linha de saída do xmlstarletcomando:

    $ xmlstarlet sel -t -m '//div[@class="power-bar-text"]' -v 'normalize-space()' -n file.xml | sed 's/ .*//' | paste -d , -s -
    9,8,11.25,10,6,5,2,3,2.50
    

    Se o seu arquivo não for XHTML, você pode convertê-lo em algo utilizável usando

    xmlstarlet format --recover --html file.html >file.xml
    
    • 7
  2. Marcus Müller
    2023-03-27T17:04:36+08:002023-03-27T17:04:36+08:00

    Para adicionar à resposta de Kusalananda , se você tiver um HTML mais geral, talvez queira usar o BeautifulSoup em vez de esperar converter para XML (não que ele não use diferentes analisadores de XML sob o capô, a maneira como lida com a análise pode apenas seja mais elegante para o seu caso de uso).

    Você escreveria um script - mas não um bashscript, mas um script Python (isso foi escrito diretamente do topo da minha cabeça e testado apenas superficialmente)

    #! /usr/bin/env python3
    
    from bs4 import BeautifulSoup
    import sys
    
    if not len(sys.argv) == 2:
        print(
            f"expected one argument, got {len(sys.argv) - 1}:\n {' '.join(sys.argv)}",
            file=sys.stderr,
        )
        sys.exit(-1)
    
    with open(sys.argv[1]) as inputfile:
        soup = BeautifulSoup(inputfile)
    
    hits = soup.find_all("div", class_="power-bar-text")
    
    for hit in hits:
        content = hit.contents[0].strip()
        print(f"found value {content}")
    

    Salve em algum arquivo, digamos myparser.py, torne executável ( chmod 755 myparser.py) e execute com o nome do arquivo HTML como argumento ( /path/to/myparser.py /path/to/input.html).

    Tanto para o código bonito e auto-explicativo. Se você sentir a necessidade de fazer isso em seu shell, poderá condensá-lo em uma linha única. (Eu recomendo que você não faça isso; você pode incorporar o código python completo, bem legível e gerador de erros sensato acima em seu script bash em uma string/HEREDOC de várias linhas):

    infile="foo.html"
    python3 -c "from bs4 import BeautifulSoup as BS;soup=BS(open('${infile}'));print('\n'.join(tag.contents[0].strip() for tag in soup.find_all('div', class_='power-bar-text')))"
    
    • 2

relate perguntas

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

  • anexar linhas após outros arquivos linha por linha

  • Como remover uma única linha entre duas linhas

  • Reorganize as letras e compare duas palavras

  • Embaralhamento de arquivo de várias 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