Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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
share|improve this question

1 Answer 1

up vote 4 down vote accepted

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 -r0i -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 got to a terminal (there, a pipe). That is, 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
share|improve this answer
    
I actually meant to use the -f option on tail, which continuously prints lines as they come in. I didn't think this would matter, but apparently it does. With the -f option your solution doesn't work. –  Lars Mar 28 at 9:23
    
The tail -f myFile.txt | xargs -r0i -d '\n' myCmd "{}" "||" "||" seems to work! Thanks. –  Lars Mar 28 at 9:31
    
@Lars, sorry, the -i option takes an optional argument, so -i0 would not work. They should all work with tail -f except the last one, but beware that because of buffering, there will be a delay before xargs gets its input from tr. You can change that by running stdbuf -o0 tr '\n' '\0' instead of tr '\n' '\0'. –  Stéphane Chazelas Mar 28 at 9:32

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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