Skip to content
shellmap

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

Bashunix
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`.

Zshunix
tail -F /var/log/app.log

Same 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.

Fishunix
tail -F /var/log/app.log

Same external. For systemd journals (which aren't plain files), use `journalctl -fu service-name` instead — fish handles the `-f` flag transparently.

PowerShellwindows
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).

cmd.exewindows
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