Comment empêcher les xargs de fusionner mal la sortie de plusieurs processus?

17

J'utilise xargsavec l'option --max-args=0(alternativement -P 0).

Cependant, la sortie des processus est fusionnée dans le stdoutflux sans tenir compte de la séparation de ligne appropriée. Je vais donc souvent me retrouver avec des lignes telles que:

<start-of-line-1><line-2><end-of-line-1>

Comme j'utilise egrepavec ^dans mon modèle sur la xargssortie entière, cela gâche mon résultat.

Existe-t-il un moyen de forcer l' xargsécriture des sorties de processus dans l'ordre (n'importe quel ordre, tant que la sortie d'un processus est contiguë)?

Ou une autre solution?

Modifier: plus de détails sur le cas d'utilisation:

Je souhaite télécharger et analyser des pages Web à partir de différents hôtes. Comme chaque page prend environ une seconde à charger et qu'il y a quelques dizaines de pages, je veux paralléliser les demandes.

Ma commande a la forme suivante:

echo -n $IPs | xargs --max-args=1 -I {} --delimiter ' ' --max-procs=0 \
wget -q -O- http://{}/somepage.html | egrep --count '^string'

J'utilise bash et pas quelque chose comme Perl car les adresses IP hôtes (la variable $ IPs) et certaines autres données proviennent d'un fichier bash inclus.

Christoph Wurm
la source
Pouvez-vous un exemple plus complet de votre question? Il n'est pas clair comment ou pourquoi vous utilisez actuellement xargs.
Caleb
La solution à cela sera difficile, il faut utiliser des descripteurs de fichiers différents pour les sorties standard de chaque processus et utiliser un petit serveur pour collecter les lignes. xargsne semble pas offrir une telle fonctionnalité.
Stéphane Gimenez
@Caleb Voilà, j'espère que cela vous aidera :-)
Christoph Wurm
Ce n'est certainement pas une solution légère, mais vous pourriez peut-être utiliser makela fonction de travail de, je pense que makeles lignes de sortie sont correctement fusionnées.
Stéphane Gimenez
ajoute le --line-buffereddrapeau pour egrepaider
iruvar

Réponses:

6

Cela devrait faire l'affaire:

echo -n $IPs | xargs --max-args=1 -I {} --delimiter ' ' --max-procs=0 \
  sh -c "wget -q -O- 'http://{}/somepage.html' | egrep --count '^string'" | \
  { NUM=0; while read i; do NUM=$(($NUM + $i)); done; echo $NUM; }

L'idée ici est de faire des comptes séparés et de les additionner à la fin. Peut échouer si les nombres séparés sont suffisamment importants pour être mélangés, mais cela ne devrait pas être le cas.

Stéphane Gimenez
la source
14

GNU Parallel est spécialement conçu pour résoudre ce problème:

echo -n $IPs | parallel -d ' ' -j0 wget -q -O- http://{}/somepage.html | egrep --count '^string'

Si vos IP sont dans un fichier, c'est encore plus joli:

cat IPs | parallel -j0 wget -q -O- http://{}/somepage.html | egrep --count '^string'

Pour en savoir plus, regardez la vidéo d'introduction: http://www.youtube.com/watch?v=OpaiGYxkSuQ

Ole Tange
la source
2
Bel outil! De plus, je parie que quelqu'un vous dira que le chat est inutile très bientôt.
Stéphane Gimenez
1
Je sais. Mais je le trouve plus facile à lire, et je travaille habituellement sur 48 machines de base, donc les quelques cycles d'horloge supplémentaires pour l'un des cœurs inactifs n'ont pas encore été un problème.
Ole Tange
parallèle serait parfait pour le travail s'il était dans les dépôts Debian.
Christoph Wurm
1
@Legate Debian inclut la parallelcommande de moreutils , ce qui est suffisant ici:parallel -j99 -i sh -c 'wget -q -O- http://{}/somepage.html | egrep -c "^string"' -- $IPs
Gilles 'SO- arrête d'être méchant'
@Legate checkout build.opensuse.org/package/… pour un fichier .deb et bugs.debian.org/cgi-bin/bugreport.cgi?bug=518696 pour le bug à pousser.
Ole Tange