23

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?

3 Answers 3

28

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.

4
  • sorry I don't see where "world" will come from in your example :) Commented Jul 8, 2017 at 3:30
  • From your typing it in. Commented Jul 8, 2017 at 3:32
  • 2
    And then you type world, and, lo, "world" appears in the other terminal. Commented Jul 8, 2017 at 3:34
  • "but tail -f will keep going..." Is it because contrary to cat, tail -f will ignore EOF conditions and will only stop permanently when one enters Ctrl+C (i.e. when receiving an interrupt signal)? Commented Nov 1, 2021 at 8:59
4

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, "hello\n"); 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.

-4

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

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.