Jak powstrzymać xargs przed złym łączeniem danych wyjściowych z wielu procesów?

17

Używam xargsz opcją --max-args=0(alternatywnie -P 0).

Jednak wyniki procesów są scalane ze stdoutstrumieniem bez uwzględnienia właściwego rozdzielenia linii. Więc często kończę liniami takimi jak:

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

Ponieważ używam egrepz ^moim wzorem na całej xargswyjście to jest brudząc się mój wynik.

Czy jest jakiś sposób na wymuszenie xargszapisu wyników procesu w dowolnej kolejności (w dowolnej kolejności, o ile wynik jednego procesu jest ciągły)?

Lub jakieś inne rozwiązanie?

Edycja: więcej szczegółów na temat przypadku użycia:

Chcę pobierać i analizować strony internetowe z różnych hostów. Ponieważ ładowanie każdej strony zajmuje około sekundy, a istnieje kilkadziesiąt stron, chcę zrównoważyć żądania.

Moje polecenie ma następującą postać:

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

Używam bash, a nie czegoś takiego jak Perl, ponieważ adresy IP hosta (zmienna $ IPs) i niektóre inne dane pochodzą z dołączonego pliku bash.

Christoph Wurm
źródło
Czy możesz podać pełniejszy przykład swojego pytania? Nie jest jasne, w jaki sposób i dlaczego obecnie używasz xargs.
Caleb
Rozwiązanie tego będzie trudne, należy użyć różnych deskryptorów plików dla standardowych parametrów każdego procesu i użyć małego serwera do zebrania linii. xargsnie wydaje się zapewniać takiej funkcji.
Stéphane Gimenez
@Caleb Proszę bardzo, mam nadzieję, że to pomoże :-)
Christoph Wurm
Zdecydowanie nie jest to lekkie rozwiązanie, ale być może warto skorzystać makez funkcji zadań, myślę, że odpowiednio makełączy linie wyjściowe.
Stéphane Gimenez
dodaje --line-bufferedflagę, aby egreppomóc
iruvar,

Odpowiedzi:

6

To powinno załatwić sprawę:

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; }

Chodzi o to, aby osobno policzyć i zsumować je na końcu. Może się nie powieść, jeśli osobne liczby są wystarczająco duże, aby je pomieszać, ale nie powinno tak być.

Stéphane Gimenez
źródło
14

GNU Parallel jest specjalnie zaprojektowany, aby rozwiązać ten problem:

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

Jeśli twoje adresy IP znajdują się w pliku, jest jeszcze ładniejsze:

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

Aby dowiedzieć się więcej, obejrzyj wideo wprowadzające: http://www.youtube.com/watch?v=OpaiGYxkSuQ

Ole Tange
źródło
2
Ładne narzędzie! Założę się też, że ktoś powie ci wkrótce, że kot jest bezużyteczny.
Stéphane Gimenez
1
Wiem. Ale łatwiej mi to czytać i zwykle pracuję na 48 rdzeniach, więc kilka dodatkowych cykli zegara dla jednego z wolnych rdzeni wciąż musi stanowić problem.
Ole Tange
Równoległość byłaby idealna do pracy, gdyby była w repozytoriach Debiana.
Christoph Wurm
1
@Legate Debian zawiera parallelpolecenie z moreutils , które jest wystarczające tutaj:parallel -j99 -i sh -c 'wget -q -O- http://{}/somepage.html | egrep -c "^string"' -- $IPs
Gilles 'SO- przestań być zły'
@ Legate Checkout build.opensuse.org/package/… dla pliku .deb i bugs.debian.org/cgi-bin/bugreport.cgi?bug=518696 dla błędu do wypchnięcia.
Ole Tange