Why xargs can’t work with tail -f?

I want tail -f /var/log/syslog | grep it with pattern “arpwatch” and send every line to myself via jabber: xmpp [email protected] using xargs

tail -f /var/log/syslog | grep arpwatch | xargs sendxmpp <a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2f5a5c4a5d414e424a6f454e4d4d4a5d015c4a5d594a5d">[email protected]</a>

no working.

but tail /var/log/syslog | grep arpwatch | sendxmpp [email protected]

works well.

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

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

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 ':%sn'

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.

Method 2

grep has the option --line-buffered to output each line immediately instead of waiting for more input.

For xargs, as suggested by @ikkachu, you need to separate by newlines instead of spaces. You can use xargs -L for that.

This should work:

tail -f /var/log/syslog 
  | grep --line-buffered arpwatch 
  | xargs -L1 sendxmpp <a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="14616771667a757971547e75767671663a677166627166">[email protected]</a>


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x