xargs – Why xargs Can’t Work with tail -f

tailxargs

I want tail -f /var/log/syslog | grep it with pattern "arpwatch" and send every line to myself via jabber: xmpp username@jabber.server using xargs

tail -f /var/log/syslog | grep arpwatch | xargs sendxmpp username@jabber.server

no working.

but tail /var/log/syslog | grep arpwatch | sendxmpp username@jabber.server

works well.

I think it's some fundamental thing about xargs and tail -f that I don't understand.

Best Answer

xargs command tries to collect as many input items (lines, words) as it can to one invocation of the command, and it doesn't particularly care about the timing of the input data. If the tail process is killed, or xargss buffer get filled, it will run command with the arguments it received by then. However, tail -f usually doesn't finish by itself, and the limit for command line arguments can be large, so it seems like it doesn't work at all.

You could use xargs -n1 to have it pass only one input item at a time to command, but you'll be hit by the fact that xargs uses whitespace to split the input into items, so an input line of foo bar would cause the command to run twice.

With GNU xargs, xargs -n1 -d '\n' should do what you want: run command once for each input line, with the full line passed as a single argument.

Try, e.g. with and without the -d and -n and make note of the output timing:

$ ( echo "123 456"; sleep 1; echo foo; sleep 1; echo doo ) | xargs -d '\n' -n1 printf ':%s\n'

xargs -L 1 would also work, but it will still split the line to separate arguments, instead of passing the whole line as one argument.

Related Question