Skip to content
shellmap

group-objectBucket items by a property — sort | uniq -c equivalent across all 5 shells

Equivalents in every shell

Bashunix
sort file.txt | uniq -c

The canonical Unix idiom: `sort` first (`uniq` only deduplicates ADJACENT lines), then `uniq -c` prefixes each with its count. Add `| sort -nr` for count-descending order. For grouping by a field, pre-process with `awk` or `cut`.

Zshunix
sort file.txt | uniq -c

Same pipeline as bash. For multi-field aggregation, the portable awk idiom is `awk '{ c[$1]++ } END { for (k in c) print c[k], k }'`.

Fishunix
sort file.txt | uniq -c

Same pipeline. Fish has no native grouping primitive; the awk idiom above works unchanged.

PowerShellwindows
Get-Content file.txt | Group-Object

Aliased as `group`. Returns `GroupInfo` objects with `.Count`, `.Name` (the property value), and `.Group` (the array of items in the bucket). `-Property <name>` groups by that property; `-NoElement` omits `.Group` for count-only output; `-AsHashTable` returns a Hashtable keyed by the property — perfect for lookups.

cmd.exewindows
sort file.txt | find /c /v ""

cmd has NO native count-by-value. The `find /c /v ""` trick counts ALL non-empty lines but not per-value. For real grouping, shell out: `powershell -Command "Get-Content file.txt | Group-Object | Select Count,Name"`.

Worked examples

Count occurrences of each line and sort by frequency

Bash
sort access.log | uniq -c | sort -nr
PowerShell
Get-Content access.log | Group-Object | Sort-Object Count -Descending

Group running processes by name; show top 5 by total memory

PowerShell
Get-Process | Group-Object Name | Sort-Object @{e={($_.Group|Measure-Object WS -Sum).Sum}} -Descending | Select-Object -First 5

Build a hashtable lookup of CSV rows by department

PowerShell
Import-Csv users.csv | Group-Object Department -AsHashTable -AsString

Gotchas

  • `Group-Object` MATERIALISES every input into memory — it cannot stream. On multi-GB inputs this blows the heap. The Unix `sort | uniq -c` pipeline DOES stream (sort spills to disk via `$TMPDIR`), so for huge files it remains the faster and more reliable choice even from pwsh: `Get-Content -Raw huge.txt | & sort | & uniq -c` (on a pwsh host with the GNU tools on PATH).
  • `-AsHashTable` requires `-AsString` when the property values aren't inherently strings — otherwise the resulting Hashtable keys are objects you can't look up by string. `Group-Object Department -AsHashTable -AsString` is the safe idiom for `Import-Csv` results.
  • `-Property` accepts a script block for computed groupings: `Get-ChildItem | Group-Object { $_.LastWriteTime.Year }` buckets files by year. Multiple properties group by the COMPOSITE: `Group-Object Department,Title` returns one bucket per `(Department, Title)` pair, with `.Name` rendered as `'Engineering, Senior'`.
  • Without `-NoElement`, the `.Group` property holds the FULL array of grouped objects — fine for small inputs, but a memory hog when grouping millions of items just to get counts. Pass `-NoElement` for count-only output; the working set is ~10× smaller on large inputs.
  • Case sensitivity: `Group-Object` is CASE-INSENSITIVE by default for string keys (`'Red'` and `'red'` go into the same bucket). Pass `-CaseSensitive` to split them. The Unix `sort | uniq -c` pipeline is case-sensitive by default — set `LC_ALL=C` if you also need byte-exact comparison (no Unicode normalisation).

WSL & PowerShell Core notes

pwsh`Group-Object` is identical on every pwsh platform — pure .NET, no native dependencies. Memory behaviour is consistent: always loads the full input. For very large inputs on any platform, the streaming `sort | uniq -c` pipeline is preferable; on pwsh you can mix them by invoking the system tools via `& sort` / `& uniq` (Linux/macOS) or via Git for Windows / WSL on the Windows side (native Windows ships `sort.exe` but no `uniq.exe`).
WSLInside WSL bash, the `sort | uniq -c` pipeline is fast and spills to disk. From Windows-side pwsh you can invoke WSL for the streaming pipeline: `Get-Content big.log | wsl sort | wsl uniq -c` — bytes flow through the WSL boundary cleanly. Conversely, `Group-Object` inside pwsh-on-WSL works identically to native Linux pwsh; only the initial file read pays the DrvFs perf penalty when sourcing from `/mnt/c/...`.

Related commands