tailShow the last lines of a file and follow it live
tail prints the end of a file, where logs keep their newest entries, and with -f keeps the file open and prints new lines as they're written. tail -F also survives log rotation. It's the first thing you run while reproducing a bug or watching a deploy.
tail [-n [+]NUM | -c [+]NUM] [-f | -F] [--pid=PID] [FILE]...A user reports an error a minute ago; you want the newest log lines first.
tailPrint the end of a file.
For a regular file, tail seeks to the end and reads backwards in blocks until it has seen enough newlines, so tail on a 50 GB log is instant. -n +N instead reads forward and starts at line N. With -f, tail then keeps the file descriptor open and waits for changes, using inotify on Linux (a kernel notification when the file is modified) with a periodic check as fallback, and prints whatever was appended. Because it follows the open descriptor, plain -f stays attached to the same inode: after logrotate renames app.log to app.log.1 and the app starts a new app.log, tail -f keeps watching the old, now silent file. -F (--follow=name --retry) re-checks the path, notices when the name points to a different inode or appears after being missing, and reopens it. If a file shrinks (truncated by copytruncate or : > file), tail reports 'file truncated' and continues from the new end. --pid makes tail exit when the given process dies.
tail -f follows the open file, so it loses the log after rotation; tail -F follows the name and reopens it.
The app holds app.log open and appends lines to it. The file is inode 1048602.
-n NLast N lines (default 10)-n +NStart at line N to the end (skip N-1 lines)-c NLast N bytes (-c +N: from byte N)-fFollow the open file: print appended data as it arrives-FFollow by name and retry: survives rotation and recreation--pid=PIDWith -f, stop following when process PID exits-s SECWith -f, check interval when polling (default 1s)-q / -vNever / always print ==> file <== headerstail -f app.log on a log that rotates-f follows the open descriptor; after a rename-based rotation it watches the old file and shows nothing new.
tail -F app.logtail -f app.log | grep ERROR | awk '{print $1}'grep buffers its output when writing to a pipe, so lines reach awk late or in bursts.
tail -f app.log | grep --line-buffered ERROR | awk '{print $1; fflush()}'tail -n 100000 app.log | less to browse a big logYou copy a huge chunk through a pipe and lose less's ability to read the file directly.
less +G app.log (opens at the end, can scroll back through the whole file)Watching /var/log/app/app.log while the service logs to the journalMany systemd services log to stdout, which goes to journald, not to a file.
journalctl -u app -fTry these on a Linux machine of your own. Each task has a hint and a solution.
Show the last 20 lines of ~/logs/app.log.
Print ~/data/orders.csv without its header line and count the data rows.
Follow ~/logs/app.log live in one terminal and append a line to it from another (or the same, in the background). Then stop with Ctrl+C.
Simulate a rotation: follow ~/logs/rot.log with -f in the background, rename it, create a new one and append to it. Compare with -F.
tailShow the last lines of a file and follow it live
tail prints the end of a file, where logs keep their newest entries, and with -f keeps the file open and prints new lines as they're written. tail -F also survives log rotation. It's the first thing you run while reproducing a bug or watching a deploy.
tail [-n [+]NUM | -c [+]NUM] [-f | -F] [--pid=PID] [FILE]...A user reports an error a minute ago; you want the newest log lines first.
tailPrint the end of a file.
For a regular file, tail seeks to the end and reads backwards in blocks until it has seen enough newlines, so tail on a 50 GB log is instant. -n +N instead reads forward and starts at line N. With -f, tail then keeps the file descriptor open and waits for changes, using inotify on Linux (a kernel notification when the file is modified) with a periodic check as fallback, and prints whatever was appended. Because it follows the open descriptor, plain -f stays attached to the same inode: after logrotate renames app.log to app.log.1 and the app starts a new app.log, tail -f keeps watching the old, now silent file. -F (--follow=name --retry) re-checks the path, notices when the name points to a different inode or appears after being missing, and reopens it. If a file shrinks (truncated by copytruncate or : > file), tail reports 'file truncated' and continues from the new end. --pid makes tail exit when the given process dies.
tail -f follows the open file, so it loses the log after rotation; tail -F follows the name and reopens it.
The app holds app.log open and appends lines to it. The file is inode 1048602.
-n NLast N lines (default 10)-n +NStart at line N to the end (skip N-1 lines)-c NLast N bytes (-c +N: from byte N)-fFollow the open file: print appended data as it arrives-FFollow by name and retry: survives rotation and recreation--pid=PIDWith -f, stop following when process PID exits-s SECWith -f, check interval when polling (default 1s)-q / -vNever / always print ==> file <== headerstail -f app.log on a log that rotates-f follows the open descriptor; after a rename-based rotation it watches the old file and shows nothing new.
tail -F app.logtail -f app.log | grep ERROR | awk '{print $1}'grep buffers its output when writing to a pipe, so lines reach awk late or in bursts.
tail -f app.log | grep --line-buffered ERROR | awk '{print $1; fflush()}'tail -n 100000 app.log | less to browse a big logYou copy a huge chunk through a pipe and lose less's ability to read the file directly.
less +G app.log (opens at the end, can scroll back through the whole file)Watching /var/log/app/app.log while the service logs to the journalMany systemd services log to stdout, which goes to journald, not to a file.
journalctl -u app -fTry these on a Linux machine of your own. Each task has a hint and a solution.
Show the last 20 lines of ~/logs/app.log.
Print ~/data/orders.csv without its header line and count the data rows.
Follow ~/logs/app.log live in one terminal and append a line to it from another (or the same, in the background). Then stop with Ctrl+C.
Simulate a rotation: follow ~/logs/rot.log with -f in the background, rename it, create a new one and append to it. Compare with -F.