Gerando múltiplos spards paralelos e armazenando resultados em uma matriz bash para ser bem impresso quando todos os wgets são feitos

5

Eu tenho uma longa lista de URLs no meu próprio site listado em um arquivo de texto separado de retorno de carro. Então, por exemplo:

  • link
  • link
  • link

Eu preciso gerar um número de wgets paralelos para acertar cada URL duas vezes, verificar e recuperar um cabeçalho específico e, em seguida, salvar os resultados em uma matriz que desejo gerar em um relatório legal.

Eu tenho parte do que eu quero usando o seguinte comando xargs:

xargs -x -P 20 -n 1 wget --server-response -q -O - --delete-after<./urls.txt 2>&1 | grep Caching

A questão é como eu executo este comando duas vezes e armazeno o seguinte:

  1. O hit do URL
  2. O primeiro resultado do grep no cabeçalho do Cache
  3. O segundo resultado do grep no cabeçalho do Cache

Assim, a saída deve ser algo como:

=====================================================
http:/www.mysite.com/url1.html
=====================================================
First Hit: Caching: MISS
Second Hit: Caching: HIT

=====================================================
http:/www.mysite.com/url2.html
=====================================================
First Hit: Caching: MISS
Second Hit: Caching: HIT

E assim por diante.

Ordenar que os URLs não sejam necessariamente uma preocupação, desde que o (s) cabeçalho (s) estejam associados (s) ao URL.

Por causa do número de URLs que preciso atingir vários URLs em paralelo, não em série, caso contrário, será muito longo.

O truque é como obter vários alertas paralelos e armazenar os resultados de maneira significativa. Eu não sou casado com o uso de um array se existe uma maneira mais lógica de fazer isso (talvez escrever em um arquivo de log?)

Algum guru bash tem alguma sugestão de como eu poderia proceder?

    
por Brad 10.06.2013 / 14:15

3 respostas

3

Crie um pequeno script que faça a coisa certa com um único URL (com base no código de Terdon):

#!/bin/bash

url=$1
echo "=======================================";
echo "$url"
echo "=======================================";
echo -n "First Hit: Caching: ";
wget --server-response -q -O - $url 2>&1 | grep Caching >/dev/null
if [ $? == 0 ]; then echo HIT; else echo MISS; fi;
echo -n "Second Hit: Caching: ";      
wget --server-response -q -O - $url 2>&1 | grep Caching >/dev/null
if [ $? == 0 ]; then echo HIT; else echo MISS; fi; echo "";

Em seguida, execute este script em paralelo (digamos, 500 jobs por vez) usando o GNU Parallel:

cat urls.txt | parallel -j500 my_script

O GNU Parallel fará com que a saída de dois processos nunca seja misturada - uma garantia que xargs não fornece.

Você pode encontrar mais sobre o GNU Parallel em: link

Você pode instalar o GNU Parallel em apenas 10 segundos com:

wget -O - pi.dk/3 | sh 

Assista ao vídeo de introdução no link

    
por 11.06.2013 / 11:54
0

Uma solução trivial seria registrar a saída de cada um dos comandos wget em um arquivo separado e usar cat para mesclá-los posteriormente.

    
por 10.06.2013 / 14:19
0

Assumirei que seu arquivo é de nova linha, não de retorno de carro separado, porque o comando que você fornece não funcionará com um arquivo \r separado.

Se o seu arquivo estiver usando \r em vez de \n para fins de linha, altere-o para usar \n executando este:

perl -i -pe 's/\r/\n/g' urls.txt 

Se você estiver usando os finais de linha estilo Windows ( \r\n ), use este:

perl -i -pe 's/\r//g' urls.txt 

Agora, quando você tiver seu arquivo no formato Unix, se não se importar que seus trabalhos não sejam executados paralelamente , será possível fazer algo assim:

while read url; do 
  echo "=======================================";
  echo "$url"
  echo "=======================================";
  echo -n "First Hit: Caching: ";
  wget --server-response -q -O - $url 2>&1 | grep Caching >/dev/null
  if [ $? == 0 ]; then echo HIT; else echo MISS; fi;
  echo -n "Second Hit: Caching: ";      
  wget --server-response -q -O - $url 2>&1 | grep Caching >/dev/null
  if [ $? == 0 ]; then echo HIT; else echo MISS; fi; echo "";
done < urls.txt

UPDATE em resposta ao seu comentário:

Se você tem 22.000 URLs, posso realmente entender por que você quer fazer isso em paralelo. Uma coisa que você pode tentar é criar arquivos tmp:

(while read url; do 
 ( 
  echo "=======================================";
  echo "$url"
  echo "=======================================";
  echo -n "First Hit: Caching: ";
  wget --server-response -q -O - $url 2>&1 | grep Caching >/dev/null
  if [ $? == 0 ]; then echo HIT; else echo MISS; fi;
  echo -n "Second Hit: Caching: ";      
  wget --server-response -q -O - $url 2>&1 | grep Caching >/dev/null
  if [ $? == 0 ]; then echo HIT; else echo MISS; fi; 
  echo ""; ) > 'mktemp urltmpXXX' 2>/dev/null&
done < urls.txt )

Existem dois subshells lançados lá, o primeiro, (while ... < urls.txt) é apenas para suprimir as mensagens de conclusão . O segundo ( ( echo "=== ... ) > mktemp urltmpXXX ) está lá para coletar todas as saídas de um determinado URL em um arquivo.

O script acima criará 22.000 arquivos tmp chamados urltmpXXX , em que XXX será substituído por tantos caracteres aleatórios. Como os arquivos tmp terão 6 linhas de texto quando todos tiverem terminado, você poderá monitorar (e, opcionalmente, excluir os arquivos) com este comando:

b='awk 'END{print NR}' urls.txt'; 
while true; do 
 a='wc -l urltmp* | grep total | awk '{print $1}'';     
 if [ $a == $((6 * $b)) ]; then cat urltmp* > urls.out; break; 
  else sleep 1; fi; 
done

Agora, o outro problema é que isso iniciará 22000 tarefas de uma só vez. Dependendo do seu sistema, isso pode ou não ser um problema. Uma maneira de contornar isso é split do arquivo de entrada e, em seguida, executar o loop acima uma vez para cada arquivo.

    
por 10.06.2013 / 19:18