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.logtail -n <count> <file> — Show the last N lines of a file.
tail -n 50 access.logtail -<count> <file> — Shorthand for -n. Show the last N lines.
tail -20 error.logtail -n +<line> <file> — Show all lines starting from line N (skip the first N-1 lines).
tail -n +2 data.csvFollow Mode (Real-Time Monitoring)
tail -f <file> — Follow a file. Output new lines as they are appended in real-time.
tail -f /var/log/syslogtail -f <file1> <file2> — Follow multiple files simultaneously with filename headers.
tail -f /var/log/nginx/access.log /var/log/nginx/error.logtail -F <file> — Follow with retry. Keeps following even if the file is rotated or recreated.
tail -F /var/log/app.logtail -f -n <count> <file> — Show the last N lines and then continue following.
tail -f -n 50 /var/log/syslogtail -f -n 0 <file> — Follow a file showing only new lines from this moment (no history).
tail -f -n 0 /var/log/app.logtail -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.logFollow 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.bintail -c <size>K <file> — Show the last N kilobytes. Supports K, M, G suffixes.
tail -c 1M large-file.logtail -c +<offset> <file> — Show all bytes starting from byte N (skip first N-1 bytes).
tail -c +100 data.binMultiple Files
tail <file1> <file2> — Show the last 10 lines of each file with filename headers.
tail error.log access.logtail -n <count> <file1> <file2> — Show the last N lines of multiple files.
tail -n 5 *.logtail -q <file1> <file2> — Quiet mode. Suppress filename headers when showing multiple files.
tail -q -n 1 *.csvtail -v <file> — Verbose mode. Always show filename header, even for a single file.
tail -v -n 5 data.txtPipelines
<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 1sort <file> | tail -n <count> — Show the last N items after sorting (e.g. largest values).
du -sh */ | sort -h | tail -n 5Common Patterns
tail -n +2 <file> — Skip the header line and show all remaining data lines.
tail -n +2 data.csvhead -n <end> <file> | tail -n <count> — Extract a specific range of lines from a file.
head -n 20 data.txt | tail -n 5tail -n +<start> <file> | head -n <count> — Alternative range extraction: start at line N and take M lines.
tail -n +10 data.txt | head -n 5tail -f /var/log/*.log — Monitor all log files in a directory simultaneously.
tail -f /var/log/nginx/*.logtail -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.logtail -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
- GNU Coreutils manual: tail – complete reference for every option
- man7.org: tail(1) – the Linux manual page