Tail a log file in real time
Follow a growing log file as new lines are appended (`tail -f`-style).
How to tail a log file in real time in each shell
tail -f /var/log/app.log`tail -f` opens the file and prints new bytes as they're appended. `-n 100` starts with the last 100 lines for context. `-F` is critical for ROTATED logs — `-f` follows the FILE descriptor (breaks if the file gets rotated/renamed); `-F` follows the FILENAME (re-opens after rotation). Always use `-F` for log files managed by `logrotate`.
tail -F /var/log/app.logSame external `tail`. macOS BSD `tail` has `-F` (follow-by-name) since at least 10.6. For multi-file follow: `tail -F /var/log/app.log /var/log/error.log` — each line is prefixed with `==> /path <==` when the source changes.
tail -F /var/log/app.logSame external. For systemd journals (which aren't plain files), use `journalctl -fu service-name` instead — fish handles the `-f` flag transparently.
Get-Content /var/log/app.log -Wait -Tail 10`-Wait` is the equivalent of `tail -f`. `-Tail N` starts with the last N lines (default: all). Polls every 1 second by default — set `-WaitTimeout` (pwsh 7.4+) to tune. For ROTATED logs, `-Wait` follows the file descriptor — if the file is rotated, you need to restart `Get-Content`. There's no pwsh-native equivalent of `tail -F` (follow-by-name).
powershell -Command "Get-Content app.log -Wait -Tail 10"cmd has NO native live-tail. Shell out to pwsh (`powershell -Command ...`) which IS available on Windows 10+ by default. The `more` command is line-mode-only — doesn't follow. Older Windows-only alternative: SysInternals `tail.exe` (free, separate download).
Equivalents listed for Bash, Zsh, Fish, PowerShell, cmd.exe.
Gotchas & notes
- **Log rotation breaks `tail -f`**: most production logs are rotated by `logrotate` (Linux) / IIS log roller / etc. With `-f` (lowercase f), tail holds the original file descriptor — after rotation, the file is renamed (`app.log → app.log.1`) and a NEW file is created, and tail continues reading from the now-stale rotated file. `-F` re-opens by NAME after each EOF / unlink, catching the new file. Always default to `-F` for production logs.
- **Distinct from "watch a file for changes"**: this task is "follow a file that GROWS by APPEND" (the normal log-file pattern). `/task/watch-file-for-changes` is about detecting CONTENT CHANGES (saves, overwrites) which uses inotify / fswatch — different mechanism, different use case. Log-tail uses lightweight polling or inotify on size-changes; file-watch uses inotify on attribute-changes.
- **systemd journals are NOT plain files**: on systemd-managed Linux (most distros since ~2015), services write to the journal binary store at `/var/lib/systemd/journal/`, NOT to `/var/log/app.log`. To follow: `journalctl -fu service-name` (`-f` follow, `-u` unit). For traditional file-based logs of a systemd service: check `/var/log/journal/*` or configure `ForwardToSyslog=yes` in the service. macOS uses Unified Logging (`log stream --predicate 'subsystem == "com.example.app"'`) — also not plain files.
- **Performance — polling vs inotify**: GNU `tail -f` uses inotify on Linux (1ms latency, near-zero CPU). pwsh `Get-Content -Wait` polls every 1s (1s latency, slight CPU). For high-throughput log following (>1000 lines/sec), GNU tail is more responsive. For occasional check-ins, the polling overhead is negligible.
Related commands
Related tasks
- Watch a file for changes— React when a file is modified — for tail-style log viewing, hot-reload tooling, or "wait until this completes" automation.
- Grep recursively with context lines— Search a directory tree for a pattern and print N lines of surrounding context for each match — for code archaeology, log spelunking, or config-file forensics.