Convert newlines to null-delimited when using tail

tailtext processingxargs

How can I change the output from tail to use null-terminated lines instead of newlines?

My question is similar to this one: How to do `head` and `tail` on null-delimited input in bash?, but differs in that I want to do something like:

tail -f myFile.txt | xargs -i0 myCmd {} "arg1" "arg2"

I am not using find, and so cannot use -print0

All this is to avoid the error that occurs in xargs:

xargs: unmatched double quote;
    by default quotes are special to xargs unless you use the -0 option

Best Answer

If you want that last 10 lines:

tail myFile.txt | tr '\n' '\0' | xargs -r0i myCmd {} arg1 arg2

But with GNU xargs, you can also set the delimiter to newline with:

tail myFile.txt | xargs -ri -d '\n' myCmd {} arg1 arg2

(-0 is short for -d '\0').

Portably, you can also simply escape every character:

tail myFile.txt | sed 's/./\\&/g' | xargs -I{} myCmd {} arg1 arg2

Or quote each line:

tail myFile.txt | sed 's/"/"\\""/g;s/.*/"&"/' | xargs -I{} myCmd {} arg1 arg2

If you want the 10 last NUL-delimited records of myFile.txt (but then that wouldn't be a text file), you'd have to convert the \n to \0 before calling tail which would mean the file will have to be read fully:

tr '\n\0' '\0\n' < myFile.txt |
  tail |
  tr '\n\0' '\0\n' |
  xargs -r0i myCmd {} arg1 arg2

Edit (since you changed the tail to tail -f in your question):

The last one above obviously doesn't make sense for tail -f.

The xargs -d '\n' one will work, but for the other ones, you'll have a buffering problem. In:

tail -f myFile.txt | tr '\n' '\0' | xargs -r0i myCmd {} arg1 arg2

tr buffers its output when it doesn't go to a terminal (here, a pipe). I.E., it will not write anything until it has accumulated a buffer full (something like 8kiB) of data to write. Which means myCmd will be called in batches.

On a GNU or FreeBSD system, you can alter the buffering behavior of tr with the stdbuf command:

tail -f myFile.txt | stdbuf -o0 tr '\n' '\0' |
  xargs -r0i myCmd {} arg1 arg2
Related Question