22

I'm using xargs with the option --max-args=0 (alternatively -P 0).

However, the output of the processes is merged into the stdout stream without regard for proper line separation. So I'll often end up with lines such as:

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

As I'm using egrep with ^ in my pattern on the whole xargs output this is messing up my result.

Is there some way to force xargs to write the process outputs in order (any order, as long as the output of one process is contiguous)?

Or some other solution?

Edit: more details about the use case:

I want to download and parse web pages from different hosts. As every page takes about a second to load and there are a few dozen pages I want to parallelize the requests.

My command has the following form:

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

I use bash and not something like Perl because the host IPs (the $IPs variable) and some other data comes from an included bash file.

6
  • Can you can a more complete example to your question? It is not clear how or why you are currently using xargs.
    – Caleb
    Jul 30, 2011 at 15:20
  • The solution to this will be tough, one need to use different file descriptors for stdout's of each process and use a small server to collect the lines. xargs doesn't seem to provide such a feature. Jul 30, 2011 at 15:59
  • @Caleb There you go, hope this helps :-) Jul 30, 2011 at 16:19
  • Definitely not a lightweight solution, but maybe you could use make's jobs feature, I think make merges output lines properly. Jul 30, 2011 at 16:22
  • does adding the --line-buffered flag to egrep help
    – iruvar
    Oct 8, 2015 at 19:46

2 Answers 2

18

GNU Parallel is specifcally designed to solve this problem:

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

If your IPs are in a file it is even prettier:

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

To learn more watch the intro video: http://www.youtube.com/watch?v=OpaiGYxkSuQ

8
  • 3
    Nice tool! Also, I'm betting that someone will tell you that cat is useless very soon. Jul 30, 2011 at 19:31
  • 1
    I know. But I find it easier to read, and I usually work on 48 core machines, so the few extra clock cycles for one of the idle cores has yet to be a problem.
    – Ole Tange
    Jul 30, 2011 at 19:55
  • parallel would be perfect for the job if it was in the Debian repositories. Jul 31, 2011 at 10:41
  • 1
    @Legate Debian includes the parallel command from moreutils, which is sufficient here: parallel -j99 -i sh -c 'wget -q -O- http://{}/somepage.html | egrep -c "^string"' -- $IPs Jul 31, 2011 at 22:05
  • @Legate checkout build.opensuse.org/package/… for a .deb file and bugs.debian.org/cgi-bin/bugreport.cgi?bug=518696 for the bug to push.
    – Ole Tange
    Aug 3, 2011 at 21:21
7

This should do the trick:

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

The idea here is to make separate counts and sum these at the end. Might fail if the separate counts are big enough to be mixed, but it should not be the case.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.