NAME
test, [ —
validate textual, numeric, or file
predicate
SYNOPSIS
test |
[!] (
expr )
[{-a, -o}
expr]… |
test |
[!] string
{=, !=,
<, >}
string, file
{-ef, -nt,
-ot} file
[{-a, -o}
expr]… |
test |
[!] -t
fd, {-n,
-z} string,
{-e, -s,
-f, -d,
-c, -b,
-p, -S,
-O, -G,
-r, -w,
-x, -u,
-g, -k,
-N} file,
{-h, -L}
path [{-a,
-o} expr]… |
test |
[!] integer
{-lt, -le,
-eq, -ne,
-ge, -gt}
integer [{-a,
-o} expr]… |
test |
[!] string
[{-a, -o}
expr]… |
test |
[ |
[!] (
expr )
[{-a, -o}
expr]… ] |
[ |
[!] string
{=, !=,
<, >}
string, file
{-ef, -nt,
-ot} file
[{-a, -o}
expr]… ] |
[ |
[!] -t
fd, {-n,
-z} string,
{-e, -s,
-f, -d,
-c, -b,
-p, -S,
-O, -G,
-r, -w,
-x, -u,
-g, -k,
-N} file,
{-h, -L}
path [{-a,
-o} expr]…
] |
[ |
[!] integer
{-lt, -le,
-eq, -ne,
-ge, -gt}
integer [{-a,
-o} expr]…
] |
[ |
[!] string
[{-a, -o}
expr]… ] |
[ |
] |
DESCRIPTION
Exits with the result of the specified boolean expression. With no expression, exits false.
Operators
In chunked descending precedence, except all unary operators are
equiprecedent; -ao left-associative.
True if:
(expr)- expr
!expr- expr is not true.
- expr
-aexpr - Both expressions are.
- expr
-oexpr - Either expression is.
- string
=string - The strings are identical.
- string
!=string - The strings are not identical.
- string-l
<string-r - string-l is ordered before string-r in the current locale's collation sequence.
- string-l
>string-r - string-l is ordered after string-r in the current locale's collation sequence.
- file
-effile - The files correspond to the same file — lie on the same device and point at the same i-node.
- file-l
-ntfile-r - The modification time of file-l is earlier than that of file-r or if file-l exists but file-r doesn't.
- file-l
-otfile-r - The modification time of file-l is later than that of file-r or if file-r exists but file-l doesn't.
-tfd- File descriptor fd corresponds to a teletype.
-nstring- string is not empty.
-zstring- string is empty.
-efile- file exists.
-sfile- file's size is non-zero.
-ffile- file is a regular file.
-dfile- file is a directory.
-cfile- file is a character device.
-bfile- file is a block device.
-pfile- file is a named pipe (FIFO).
-Sfile- file corresponds to a UNIX-domain socket.
-hpath,-Lpath- path is a symbolic link.
-Ofile- file is owned by the process' effective user ID.
-Gfile- file is owned by the process' effective group ID.
-rfile- file could be read by the process.
-wfile- file could be written by the process.
-xfile- file could be executed (searched) by the process.
-ufile- file is set-user-ID.
-gfile- file is set-group-ID.
-kfile- file is sticky.
-Nfile- file's modification time is after its access time.
- int-l
-ltint-r - int-l < int-r
- int-l
-leint-r - int-l ≤ int-r
- int-l
-eqint-r - int-l = int-r
- int-l
-neint-r - int-l ≠ int-r
- int-l
-geint-r - int-l ≥ int-r
- int-l
-gtint-r - int-l > int-r
- string
-nstring
EXIT STATUS
- 0
- The expression evaluated true.
- 1
- The expression evaluated false.
- 2
- Syntax error in expression or non-integer passed to
-tor an arithmetic operator.
EXAMPLES
A short, edited, idiomatic extract from kernel-install(8):
#!/bin/sh[-z"$MACHINE_ID"]&&[-f/etc/machine-id]&&read-rMACHINE_ID</etc/machine-id[-z"$MACHINE_ID"]&&MACHINE_ID=Default["$VERBOSE"-ge3]&&echo"Machine ID:$MACHINE_ID"forsuffin"$MACHINE_ID" "Default" "loader/entries";doforprefin"/efi" "/boot" "/boot/efi";doif[-d"$pref/$suff"];thenBOOT_ROOT="$pref"break2fidonedoneif[-z"$layout"];thenif[-d"$BOOT_ROOT/$MACHINE_ID"];thenlayout="bls-efi"elselayout="legacy"fifi
SEE ALSO
STANDARDS
Conforms to IEEE Std 1003.1-2024
(“POSIX.1”); -O,
-G, -k are extensions;
-k originates from CB-UNIX,
-N from
bash(1), the rest from the KornShell,
() and -ao conform
to IEEE Std 1003.1-2008 (“POSIX.1”),
are marked obsolete there and removed in IEEE Std
1003.1-2024 (“POSIX.1”), and for good reason —
the expression grammar is very loose and easy to throw off with malicious
input. Chain multiple test invocations with
&& and || instead,
though be wary of precedence (rather, the comparative lack thereof without
an explicit {}).
HISTORY
Appears prototypically in Version 2 AT&T UNIX as if(I):
NAMEif -- conditional commandSYNOPSISif expr command [ arg1 ... ]
- !
- unary negation operator
- -a
- binary and operator
- -o
- binary or operator
- (
expr) - parentheses for grouping.
-c as present-day, including
-ao precedence.
The BUGS state:
Version 3 AT&T UNIX removes
-c.
Version 5 AT&T UNIX adds an expr of
if exclusion would hint at funny business, but there
is none — everything up to the } is passed to
execv(2) in the child, with the period-appropriate
PATH emulation. This makes
if {
whatever a b c }
something q w eif whatever a
b c; then something q w
e; fiVersion 7 AT&T UNIX makes
if a reserved word in the shell, as present-day, and
replaces
if(I) with test supporting
(), !,
-ao, =,
!=, -tnzsfdrw,
-lt, -le,
-eq, -ne,
-ge, -gt,
and the plain string. -t,
when not followed by an argument, defaults to -t
1. -lt,
-le, -eq,
-ne, -ge,
-gt, instead of integers, can be provided with
-l string, resolving to the
length of string.
CB-UNIX at or before version 2.3 adds
-xcbugk and drops -l.
CB-UNIX was, among others, the basis for AT&T System III UNIX, which sees the same implementation, but, curiously, only as a sh(1) built-in.
AT&T System V Release 1
UNIX adds -p. AT&T
System V Release 4 UNIX adds
-h, alters -f to match any
non-directories if /usr/ucb is in the
PATH.
4.4BSD adds all CB-UNIX operators,
-eph, and &| as aliases
for -ao to a Version 7
AT&T UNIX base.
Version 7 AT&T UNIX accepts
being called as [, undocumented in the manual, but
only if it takes up the whole argument 0 (is not preceded
by a path).
CB-UNIX adds the [
expr ] syntax to the
manual.
4.4BSD checks only the final character.
IEEE Std 1003.1-2008 (“POSIX.1”) requires checking the basename, previous standards are unclear.
IEEE Std 1003.1-2024
(“POSIX.1”) adds -ef,
-nt, -ot,
-<, ->, as
present-day, and removes () and
-ao.