test — Evaluate a conditional — file tests, string and number comparisons across all 5 shells
Equivalents in every shell
test -f /etc/hostsPOSIX builtin. `[ -f /etc/hosts ]` is the same command — `[` is a synonym, and the closing `]` is a required argument. Exit 0 if true, 1 if false. For arithmetic + glob extras, prefer `[[ ]]`.
test -f /etc/hostsSame as bash. Zsh also offers `[[ ]]` extended-test syntax with safer string-comparison semantics — `[[ $var == foo ]]` does not need quoting around `$var`.
test -f /etc/hostsFish builtin. Fish has NO `[[ ]]`; `test` is the only conditional primitive. Combine results with the keywords `and` / `or` / `not` (not `&&` / `||`).
Test-Path /etc/hostsNo single `test` cmdlet. `Test-Path` handles file/directory existence; comparison operators (`-eq`, `-lt`, `-gt`, `-match`) handle everything else. Both return `$true` / `$false`, not POSIX exit codes.
if exist C:\Windows\System32 (echo yes)Cmd has no `test` keyword. The `if` builtin includes `exist`, `defined`, `errorlevel`, and `==`. Number comparison uses `equ` / `lss` / `gtr` (`if %n% gtr 10 echo big`).
Worked examples
Branch on whether a file exists
if [ -f /etc/hosts ]; then echo present; fiif [[ -f /etc/hosts ]]; then echo present; fiif test -f /etc/hosts; echo present; endif (Test-Path /etc/hosts) { "present" }if exist C:\Windows\System32\drivers\etc\hosts echo presentCompare two integers (n greater than 10)
test "$n" -gt 10 && echo big(( n > 10 )) && echo bigtest "$n" -gt 10; and echo bigif ($n -gt 10) { "big" }if %n% gtr 10 echo bigCheck whether a string variable is non-empty
[ -n "$VAR" ] && echo settest -n "$VAR"; and echo setif ($VAR) { "set" }if defined VAR echo setGotchas
- `test` / `[` REQUIRES whitespace around its arguments — `[ -f /etc/hosts ]` works, `[-f /etc/hosts]` (no spaces) is a syntax error. The `[` is a literal command name, not parser sugar.
- Unquoted variables in `[ ]` are a classic bug: `[ -n $VAR ]` becomes `[ -n ]` (always true) when `$VAR` is empty. ALWAYS double-quote: `[ -n "$VAR" ]`. Bash/zsh `[[ ]]` avoids this trap entirely.
- Bash `[[ ]]` and POSIX `[ ]` are NOT interchangeable — `[[ ]]` supports `==` pattern matching and `=~` regex, while `[ ]` does not. Scripts intended for `/bin/sh` (`#!/bin/sh`) must stay POSIX and use only `[ ]`.
- PowerShell `-eq` is CASE-INSENSITIVE for strings by default (`"A" -eq "a"` is `$true`). Use `-ceq` for case-sensitive or `-ieq` for explicit insensitive. Bash `[ "$a" = "$b" ]` is always case-sensitive — porting scripts must reconcile the difference.
- Cmd `if` does NOT support file-attribute tests (no `-x`, `-r`, etc.). The only file-related operator is `exist`. For permissions checks, drop to PowerShell `Test-Path` + ACL lookups or use `icacls` parsing.