continuous reading from named pipe (cat or tail -f)

I have configured rsyslog to log certain log events to /dev/xconsole:

*.*;cron.!=info;mail.!=info      |/dev/xconsole

/dev/xconsole is a named pipe (fifo). If I want to see what is being logged, I can do cat /dev/xconsole. I am surprised to see, that the command cat /dev/xconsole does not finish after reading the file, but instead acts as tail -f. in other words, the two commands behave the same:

cat /dev/xconsole
tail -f /dev/xconsole

Can somebody please explain why is that?

Is there any difference between the two?

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

cat keeps reading until it gets EOF. A pipe produces EOF on the output only when it gets EOF on the input. The logging daemon is opening the file, writing to it, and keeping it open — just like it does for a regular file — so EOF is never generated on the output. cat just keeps reading, blocking whenever it exhausts what’s currently in the pipe.

You can try this out yourself manually:

$ mkfifo test
$ cat test

And in another terminal:

$ cat > test
hello

There will be output in the other terminal. Then enter:

world

There will be more output in the other terminal. If you now Ctrl-D the input then the other cat will terminate too.

In this case, the only observable difference between cat and tail -f will be if the logging daemon is terminated or restarted: cat will stop permanently when the write end of the pipe is closed, but tail -f will keep going (reopening the file) when the daemon is restarted.

Method 2

There is also a difference in buffering between cat and tail -f. You can check this out:

Create pipe: mkfifo pipe

Start reading pipe using cat in background: cat pipe &

Open pipe and write to it every second: perl -MFcntl -we 'sysopen(my $fh, "pipe", O_WRONLY | O_NONBLOCK); while() {warn "written: " . syswrite($fh, "hellon"); sleep 1}'

Now try this with tail -f pipe & instead of cat. So you can see that cat prints lines as soon as they are written to pipe by perl script, while tail -f buffers them up to 4kb before printing to stdout.

Method 3

cat shows you the whole file when tail -f Shows only the last rows and follows. So if the file is short they behave the same, but if the file is big (100+ rows) you can see a clear difference between them two.

Additional information about those commands :

tail http://www.computerhope.com/unix/utail.htm

cat http://www.computerhope.com/unix/ucat.htm


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