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.50
dela é a primeira e única correspondência.
Certamente há uma maneira melhor?
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
div
nós que possuemclass
atributos com o valorpower-bar-text
, enquanto ao mesmo tempo aparamos os espaços em branco flanqueadores:Isso primeiro corresponde aos
div
nós nos quais estamos interessados e, em seguida, extrai o resultado danormalize-space()
função aplicada a esses nós correspondentes. No final,-nl
delimita cada saída com um caractere de nova linha.Ou, usando opções curtas,
Dado o fragmento de documento que você mostra, isso provavelmente resultaria em algo como o seguinte:
Isso pode ser colocado em uma única linha com vírgulas como delimitadores, passando-o por
... igual a:
Adicione algum processamento extra se desejar apenas o que ocorrer antes do primeiro espaço em cada linha de saída do
xmlstarlet
comando:Se o seu arquivo não for XHTML, você pode convertê-lo em algo utilizável usando
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
bash
script, mas um script Python (isso foi escrito diretamente do topo da minha cabeça e testado apenas superficialmente)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):