I've got a temporary file (not a fifo/pipe) that needs to be watched by multiple reader scripts. Each script uses a background process to watch the temporary file, using this code:
function file_relay {
# $1 is a regular file to read from
local bg_file
bg_file="$1"
# $2 is a fifo to relay to
local outfile
outfile="$2"
tail -f "$bg_file" | while read -r line
do
[[ ! -z "$line" ]] && { printf "%s" "$line" >>"$outfile"; }
done
}
They need to read the entire file when they start, then watch for new lines, which the above function does:
file_relay /tmp/examplefile /tmp/examplefifo &
Each script will output lines to this file as well. So it's a multiple-writer and multiple-reader situation.
The problem is that sometimes tail -f
doesn't wait for a full line to be available, even though I'm using printf
to redirect to the file and I've got newlines at the end of the strings. This causes the lines read to be corrupted, with the first word of the last line being appended at the end of the previous one, so I get:
This is one lineThis
instead of
This is one line
This is another line
I've tried to work around printf
's buffering, tail -f
's buffering as well as use sync
around writes to the file (the file is read only in the function above and I don't know how to force tail
to run sync
before attempting to read the entire line). stdbuf
doesn't seem to have any effect anywhere, nor does using -z
for tail
, or terminating strings with $'\0'
or anything else. The only thing that prevents it from happening right away is a single sync
before the while
loop starts, but that doesn't prevent it from happening after that.
Is there any way to force tail -f
to read only complete lines?