tail — Show the End of Files and Follow Logs

Practical guide to tail: show the last lines of a file and follow log files in real time with -f/-F, plus filtering and monitoring.

tail shows you the end of a file – by default the last 10 lines. Its most famous feature is follow mode -f: with it you watch a log file in real time and see new entries the moment they are written. Mind the difference between -f (follows the open file descriptor) and -F (follows the filename and reopens the file after a rotation) – for rotating logs -F is almost always the right choice. With -n +N you jump to a starting line, for instance to skip the header row of a CSV. This guide walks you through follow mode, range selection and the most important pipeline patterns.

Basic Usage

tail <file> — Show the last 10 lines of a file (default).

tail error.log

tail -n <count> <file> — Show the last N lines of a file.

tail -n 50 access.log

tail -<count> <file> — Shorthand for -n. Show the last N lines.

tail -20 error.log

tail -n +<line> <file> — Show all lines starting from line N (skip the first N-1 lines).

tail -n +2 data.csv

Follow Mode (Real-Time Monitoring)

tail -f <file> — Follow a file. Output new lines as they are appended in real-time.

tail -f /var/log/syslog

tail -f <file1> <file2> — Follow multiple files simultaneously with filename headers.

tail -f /var/log/nginx/access.log /var/log/nginx/error.log

tail -F <file> — Follow with retry. Keeps following even if the file is rotated or recreated.

tail -F /var/log/app.log

tail -f -n <count> <file> — Show the last N lines and then continue following.

tail -f -n 50 /var/log/syslog

tail -f -n 0 <file> — Follow a file showing only new lines from this moment (no history).

tail -f -n 0 /var/log/app.log

tail -f <file> --pid=<pid> — Follow a file and stop when the specified process exits.

tail -f output.log --pid=$!

tail -f -s <seconds> <file> — Follow with a custom sleep interval between checks (default 1 second).

tail -f -s 0.1 /var/log/app.log

Follow with Filtering

tail -f <file> | grep '<pattern>' — Follow a file and show only lines matching a pattern.

tail -f /var/log/syslog | grep 'ERROR'

tail -f <file> | grep --line-buffered '<pattern>' — Follow with grep using line buffering for immediate output.

tail -f access.log | grep --line-buffered '500'

tail -f <file> | grep -v '<pattern>' — Follow a file and exclude lines matching a pattern.

tail -f access.log | grep -v 'healthcheck'

tail -f <file> | grep --color '<pattern>' — Follow a file and highlight matching patterns in color.

tail -f /var/log/app.log | grep --color -E 'ERROR|WARN|$'

tail -f <file> | awk '/<pattern>/ {print}' — Follow with awk for more complex filtering and field extraction.

tail -f access.log | awk '$9 >= 500 {print}'

Byte Mode

tail -c <bytes> <file> — Show the last N bytes of a file instead of lines.

tail -c 200 data.bin

tail -c <size>K <file> — Show the last N kilobytes. Supports K, M, G suffixes.

tail -c 1M large-file.log

tail -c +<offset> <file> — Show all bytes starting from byte N (skip first N-1 bytes).

tail -c +100 data.bin

Multiple Files

tail <file1> <file2> — Show the last 10 lines of each file with filename headers.

tail error.log access.log

tail -n <count> <file1> <file2> — Show the last N lines of multiple files.

tail -n 5 *.log

tail -q <file1> <file2> — Quiet mode. Suppress filename headers when showing multiple files.

tail -q -n 1 *.csv

tail -v <file> — Verbose mode. Always show filename header, even for a single file.

tail -v -n 5 data.txt

Pipelines

<command> | tail — Show only the last 10 lines of command output.

history | tail

<command> | tail -n <count> — Show only the last N lines of command output.

git log --oneline | tail -n 5

<command> | tail -n 1 — Get only the last line of output.

wc -l *.py | tail -n 1

sort <file> | tail -n <count> — Show the last N items after sorting (e.g. largest values).

du -sh */ | sort -h | tail -n 5

Common Patterns

tail -n +2 <file> — Skip the header line and show all remaining data lines.

tail -n +2 data.csv

head -n <end> <file> | tail -n <count> — Extract a specific range of lines from a file.

head -n 20 data.txt | tail -n 5

tail -n +<start> <file> | head -n <count> — Alternative range extraction: start at line N and take M lines.

tail -n +10 data.txt | head -n 5

tail -f /var/log/*.log — Monitor all log files in a directory simultaneously.

tail -f /var/log/nginx/*.log

tail -f <file> | tee <output_file> — Follow a file and save the output to another file at the same time.

tail -f app.log | tee filtered.log

tail -f <file> | while read line; do echo "$(date): $line"; done — Follow a file and prepend a timestamp to each new line.

tail -f app.log | while read line; do echo "$(date '+%H:%M:%S'): $line"; done

Conclusion

tail is the standard tool for watching log files and the counterpart to head. The key everyday decision: -f follows the file through its descriptor and "loses" it when logrotate rotates it away; -F instead follows the path and reopens the new file automatically – so for production logs -F is usually the safe choice. When filtering in real time you often need grep --line-buffered, otherwise pipeline buffering holds the output back. And remember that tail -f never ends on its own – stop it with Ctrl-C or tie it to a process lifetime with --pid.

Further Reading

  • head – show the first lines of files
  • less – page through files screen by screen (also follows with +F)
  • grep – search lines by pattern