Skip to content
shellmap

where-objectFilter pipeline objects by property — like awk or grep across all 5 shells

Equivalents in every shell

Bashunix
command | awk '$3 > 100'

For text streams, `awk` is the closest equivalent — filter rows by column predicate (`$3 > 100`). For pure line-matching the right tool is `grep "pattern"`. The big semantic gap: bash pipes carry bytes/lines, so the predicate is always re-parsed text. PowerShell passes typed objects, so `Where-Object` reads properties directly without re-parsing.

Zshunix
command | awk '$3 > 100'

Same `awk` / `grep` toolchain. Zsh adds `(#...)` glob qualifiers (`*(.L+100)` = regular files larger than 100 bytes) — closest in-shell predicate to PowerShell `Where-Object Length -gt 100` without piping. For arbitrary pipeline filtering, zsh still reaches for awk.

Fishunix
command | awk '$3 > 100'

Same external `awk` / `grep`. Fish has no native typed-object pipeline — its `string match` builtin (`string match -r 'pattern'`) is a fast in-shell `grep` for line filtering, but column-predicate filtering still goes through awk.

PowerShellwindows
Get-Process | Where-Object { $_.CPU -gt 100 }

PowerShell-native cmdlet (aliases `?` and `where`). Filters pipeline objects by a `ScriptBlock` predicate where `$_` is the current object. PS 3.0+ adds a faster comparison syntax: `Get-Process | Where-Object CPU -gt 100` (no `$_`, no braces) — works for single-condition filters. Output type matches the input type.

cmd.exewindows
command | findstr "pattern"

`findstr` filters lines by literal/regex match (`/I` case-insensitive, `/V` invert, `/R` regex). No column-aware predicate exists in cmd.exe — for arithmetic comparisons (`length > 100`) you need PowerShell or WSL. `for /f "tokens=3" %i in ...` parses columns but mixing it with filtering is verbose.

Worked examples

Filter processes using more than 100 MB of memory

Bash
ps -eo rss,comm | awk '$1 > 102400'
PowerShell
Get-Process | Where-Object { $_.WorkingSet64 -gt 100MB }

Filter files larger than 1 MB in the current directory

Bash
find . -maxdepth 1 -type f -size +1M
Zsh
print -l *(.L+1048576)
PowerShell
Get-ChildItem | Where-Object Length -gt 1MB
cmd.exe
forfiles /m * /c "cmd /c if @fsize gtr 1048576 echo @file"

Show only services that are currently running

Bash
systemctl list-units --type=service --state=running
PowerShell
Get-Service | Where-Object Status -eq Running

Gotchas

  • The legacy `Where-Object { $_.Prop -eq "value" }` `ScriptBlock` syntax and the PS 3.0+ `Where-Object Prop -eq "value"` shorthand are NOT identical: the shorthand only supports ONE comparison and the parameter set requires a comparison operator (`-eq`, `-gt`, `-like`, `-match`, etc.). Compound predicates (`$_.A -eq 1 -and $_.B -gt 2`) require the `ScriptBlock` form.
  • `Where-Object` evaluates a `ScriptBlock` per object — slow on large streams compared to `.Where()` (the array method): `(Get-Process).Where({$_.CPU -gt 100})` is ~5× faster but loses streaming (the entire input is materialised first). For one-shot pipelines, prefer `Where-Object`; for tight loops on already-materialised collections, use `.Where()`.
  • Comparison operators are case-INSENSITIVE by default (`-eq`, `-like`, `-match`). For case-sensitive comparisons prepend `c`: `-ceq`, `-clike`, `-cmatch`. This bites bash users who expect `=` to be byte-exact.
  • `-match` and `-notmatch` set the `$matches` automatic variable as a side effect — fine in interactive use, but in scripts that pipe through multiple `Where-Object -match` stages, `$matches` ends up holding the LAST match, which can surprise later code. Use `-like` (wildcard) or `-cmatch` if you don't want this side effect.
  • `$null` filtering: `Where-Object { $_ }` drops `$null`, `$false`, `0`, `''` (truthy filter) — useful but trips users expecting `WHERE NOT NULL` semantics. For explicit null filtering, write `Where-Object { $null -ne $_ }` (note the `$null` on the LEFT — PowerShell idiom to dodge a known `-ne` array gotcha).

WSL & PowerShell Core notes

pwsh`Where-Object` is identical on every pwsh platform — Windows, macOS, Linux — because it operates on .NET objects in the pipeline rather than the underlying OS. The `where` alias is REMOVED on Linux/macOS pwsh so the system `/usr/bin/where` (a Unix utility on some distros) and the BSD `which`-like binary resolve first. Always spell `Where-Object` or use the `?` alias for portable scripts.

Related commands