Grep no script bash não funcionará corretamente

1

Eu sei que há muitas perguntas semelhantes na Internet, mas não consegui encontrar uma solução para o meu problema específico.

Eu fiz este script para uma tarefa, onde quero descobrir quais combinações retornam UNLOCKED como resultado em HTML.

#!/bin/bash
for ((x4=0;x4<=4;x4++)); do
  for ((x3=0;x3<=4;x3++)); do
    for ((x2=0;x2<=4;x2++)); do
      for ((x1=0;x1<=4;x1++)); do
echo $x1 $x2 $x3 $x4
eval curl http://www.artemiosv.info/21.php?p1=$x1;p2=$x2;p3=$x3;p4=$x4
  | grep -oP '<BODY>*[\s\S]*</BODY>'
done
done
done
done

As primeiras linhas do resultado retornado, após redirecionar a saída do script em um arquivo, são:

0 0 0 0
<HTML><BODY>LOCKED</BODY></HTML>1 0 0 0
<HTML><BODY>LOCKED</BODY></HTML>2 0 0 0
<HTML><BODY>LOCKED</BODY></HTML>3 0 0 0

A partir do código HTML, que é o resultado real do comando curl , quero apenas o texto principal, no caso dessas linhas LOCKED. Mas o regex que eu usei parece não funcionar, enquanto testar o mesmo padrão fora do script funciona bem. Os resultados esperados do HTML devem ser LOCKED, UNLOCKED e acho que você encontrou o segredo.

Por que o grep tem esse problema dentro do script e o lado de fora funciona bem? Como posso consertar isso?

    
por jimkats 14.07.2016 / 03:51

2 respostas

0

Você só precisa alterar sua expressão regular para que as tags HTML sejam excluídas. Como você está usando expressões regulares compatíveis com Perl, é possível usar \K , o que significa "descartar qualquer coisa correspondente a este ponto |" para descartar o <BODY> e uma lookahead positiva para descartar o </BODY> . Você também pode usar expansões de chaves em vez da mais difícil sintaxe for((var=0;var<=lim;var++)) :

for x4 in {0..4}; do
  for x3 in {0..4}; do
    for x2 in {0..4}; do
      for x1 in {0..4}; do
        curl "http://www.artemiosv.info/21.php?p1=$x1;p2=$x2;p3=$x3;p4=$x4" 2>/dev/null |
            grep -oP '<BODY>\K[\s\S]*(?=</BODY>)'
      done
    done
  done
done

Ou, se você quer o conteúdo HTML e os valores de suas 4 variáveis, use isto:

for x4 in {0..4}; do
 for x3 in {0..4}; do
  for x2 in {0..4}; do
   for x1 in {0..4}; do
     printf '%s : %s\n' "$x1 $x2 $x3 $x4" \
        "$(curl "http://www.artemiosv.info/21.php?p1=$x1;p2=$x2;p3=$x3;p4=$x4" 2>/dev/null |
           grep -oP '<BODY>\K[\s\S]*(?=</BODY>)')"
   done
  done
done

concluído

Note que também removi o eval , pois isso não estava fazendo nada útil. Você só precisa redirecionar o stderr.

Por fim, você também pode enviar os comandos curl para o segundo plano para poder executar muitos em paralelo. Estes não são comandos muito pesados, portanto, sua máquina deve ser capaz de lidar com eles e isso irá acelerar o script significativamente. Basta adicionar um & no final da linha printf ... :

printf '%s : %s\n' "$x1 $x2 $x3 $x4" \
        "$(curl "http://www.artemiosv.info/21.php?p1=$x1;p2=$x2;p3=$x3;p4=$x4" 2>/dev/null |
            grep -oP '<BODY>\K[\s\S]*(?=</BODY>)')" &

Observe, no entanto, que o site do qual você está tentando fazer o download parece ter problemas para lidar com várias solicitações consecutivas. Mesmo quando não executado em paralelo, algumas solicitações retornam vazias (e funcionam se executadas manualmente) e, quando executadas em paralelo, o número de resultados vazios é multiplicado. Você pode querer falar com seu professor sobre como corrigir isso.

    
por terdon 14.07.2016 / 11:14
1

Me desculpe, talvez eu tenha perdido alguma coisa.

Inspecione seu comando curl no shell. Recorte o grep e execute-o. Quando faço isso, posso ver todo o retorno. Eu volto centenas de vezes

<HTML><BODY>LOCKED</BODY></HTML>

que eu acho que indica que o site está bloqueando seu esforço para raspar. Heck, apenas procure por isso:

http://www.artemiosv.info/21.php?p1=1;p2=2;p3=3;p4=4

Retorna uma página que diz simplesmente "LOCKED"

Sobre a questão do grep, o grep selecionará linhas que tenham um padrão de caractere. Ele não sub-seleciona strings lá dentro, é para isso que serve uma ferramenta como o sed. Eu acho que o grep está te dando exatamente o que você pede. Você diz que funcionou em um caso de teste, mas não consigo imaginar como.

Por que não pegar o caminho simples de executar o "web scrape" e salvar os arquivos no seu PC, então faça a grep / sed / awk magic neles. Essa é a única maneira de ter certeza do que você realmente está recebendo quando recupera as coisas. E é muito mais provável que você receba o que precisa de grep ou sed. Os tubos são úteis quando você sabe o que está fazendo e o que tem. Eu suspeito que aqui nenhuma das condições é válida.

    
por pauljohn32 14.07.2016 / 07:05