Skip to content
shellmap

tacConcatenate and print files in reverse line order across all 5 shells

Equivalents in every shell

Bashunix
tac file.txt

GNU coreutils — Linux ships it by default, macOS does NOT. The name is `cat` spelled backwards. Reads the whole file into memory by default; use `tac -s SEP` to reverse on a non-newline separator (e.g. `tac -s "---" log.txt`).

Zshunix
tac file.txt

Same external GNU tool. On macOS, install with `brew install coreutils` (provides `gtac`) or fall back to BSD `tail -r file.txt` — but `tail -r` reads the WHOLE FILE into memory and is slower on multi-GB inputs.

Fishunix
tac file.txt

Same external. Fish has no builtin reverse; pipe through `tac` (Linux) or `tail -r` (macOS / BSD). For in-shell reversal of a list variable, slice with negative step: `for x in $list[-1..1]; echo $x; end`.

PowerShellwindows
$l = Get-Content file.txt; $l[($l.Count-1)..0]

No native `tac`. The idiomatic form is index-slice in reverse: `$lines = Get-Content file.txt; $lines[($lines.Count-1)..0]`. Alternative: `[Array]::Reverse($lines); $lines` (in-place mutation). Avoid `Sort-Object` for reversal — it is O(N log N) where reversal is O(N).

cmd.exewindows
powershell -NoProfile -Command "$l=Get-Content file.txt; $l[($l.Count-1)..0]"

No native reverse. Shell out to PowerShell (one-liner above) or use a `for /f` loop with a manual stack: push each line to a temp file, then dump in pop order. The PowerShell form is far simpler — cmd has no idiomatic equivalent.

Worked examples

Print a file in reverse line order

Bash
tac file.txt
Zsh
tac file.txt
Fish
tac file.txt
PowerShell
$l = Get-Content file.txt; $l[($l.Count-1)..0]
cmd.exe
powershell -NoProfile -Command "$l=Get-Content file.txt; $l[($l.Count-1)..0]"

Print the last 50 log lines, newest first

Bash
tail -n 50 app.log | tac
Zsh
tail -n 50 app.log | tac
Fish
tail -n 50 app.log | tac
PowerShell
$l = Get-Content app.log -Tail 50; $l[($l.Count-1)..0]

Reverse log entries separated by --- markers (not by newline)

Bash
tac -s "---" log.txt
Zsh
tac -s "---" log.txt

Gotchas

  • macOS does NOT ship `tac` — it is GNU-only. BSD systems use `tail -r file.txt` for the same effect, but `tail -r` reads the entire file into memory and rejects pipes on some BSDs (you must redirect from a real file). For portable scripts, prefer `awk '{a[NR]=$0} END{for(i=NR;i>0;i--) print a[i]}'` — runs on every system.
  • `tac -s SEP` reverses on SEP, not newlines — `tac -s ""` is a no-op on most inputs. The separator is treated as a regex (`-r` makes it explicit). To reverse by paragraph (blank-line-separated), use `tac -s $'\n\n'` in bash; the literal escape `"\n\n"` does NOT work — bash needs ANSI-C `$'...'` quoting for the real newline.
  • `tac` reads the WHOLE input into memory before printing (it has to know the end). For multi-GB log files this is fine on a workstation but problematic on memory-constrained containers — pipe through `split -l 100000` first, reverse each chunk, then concatenate chunks in reverse order if memory is tight.
  • PowerShell `[Array]::Reverse($arr)` MUTATES the array IN PLACE and returns `$null`. The naive `$x = [Array]::Reverse((Get-Content file.txt))` ends up with `$x = $null`. Use `$lines = Get-Content file.txt; [Array]::Reverse($lines); $lines` or the index-slice form `$lines[($lines.Count-1)..0]` for one-line clarity.
  • Reversing a STREAM (e.g. `tail -f app.log | tac`) does NOT work as expected — `tac` waits for EOF before printing anything. For real-time newest-first viewing, page the file in reverse periodically: `watch 'tail -n 20 app.log | tac'` is the common pragmatic workaround.

WSL & PowerShell Core notes

pwshPowerShell array slicing (`$arr[($arr.Count-1)..0]`) works identically on every platform, including pwsh on Linux / macOS where `tac` exists natively but the pwsh-idiomatic form keeps the script in objects rather than text. For large files, prefer the system `tac` via subprocess to avoid loading everything into the pwsh runtime.
WSLWSL ships GNU `tac` from coreutils. Calling `wsl tac windows-file.txt` from cmd / PowerShell is the cleanest way to get GNU `tac` on Windows without installing scoop / choco. Path semantics: pass Windows paths through `wslpath -u` first, or use `/mnt/c/...` directly.

Related commands