p All operators and flags are separate arguments to the .Nm utility.
p The following primaries are used to construct .Ar expression : l -tag -width Ar t Fl b Ar file True if .Ar file exists and is a block special file. t Fl c Ar file True if .Ar file exists and is a character special file. t Fl d Ar file True if .Ar file exists and is a directory. t Fl e Ar file True if .Ar file exists (regardless of type). t Fl f Ar file True if .Ar file exists and is a regular file. t Fl g Ar file True if .Ar file exists and its set group ID flag is set. t Fl h Ar file True if .Ar file exists and is a symbolic link. t Fl k Ar file True if .Ar file exists and its sticky bit is set. t Fl n Ar string True if the length of .Ar string is nonzero. t Fl p Ar file True if .Ar file exists and is a named pipe (FIFO). t Fl r Ar file True if .Ar file exists and is readable. t Fl s Ar file True if .Ar file exists and has a size greater than zero. t Fl t Ar file_descriptor True if the file whose file descriptor number is .Ar file_descriptor is open and is associated with a terminal. t Fl u Ar file True if .Ar file exists and its set user ID flag is set. t Fl w Ar file True if .Ar file exists and is writable. True indicates only that the write flag is on. The file is not writable on a read-only file system even if this test indicates true. t Fl x Ar file True if .Ar file exists and is executable. True indicates only that the execute flag is on. If .Ar file is a directory, true indicates that .Ar file can be searched. t Fl z Ar string True if the length of .Ar string is zero. t Fl L Ar file True if .Ar file exists and is a symbolic link. This operator is retained for compatibility with previous versions of this program. Do not rely on its existence; use .Fl h instead. t Fl O Ar file True if .Ar file exists and its owner matches the effective user id of this process. t Fl G Ar file True if .Ar file exists and its group matches the effective group id of this process. t Fl S Ar file True if .Ar file exists and is a socket. t Ar file1 Fl nt Ar file2 True if .Ar file1 exists and is newer than .Ar file2 . t Ar file1 Fl ot Ar file2 True if .Ar file1 exists and is older than .Ar file2 . t Ar file1 Fl ef Ar file2 True if .Ar file1 and .Ar file2 exist and refer to the same file. t Ar string True if .Ar string is not the null string. t Ar s1 Cm = Ar s2 True if the strings .Ar s1 and .Ar s2 are identical. t Ar s1 Cm != Ar s2 True if the strings .Ar s1 and .Ar s2 are not identical. t Ar s1 Cm < Ar s2 True if string .Ar s1 comes before .Ar s2 based on the ASCII value of their characters. t Ar s1 Cm > Ar s2 True if string .Ar s1 comes after .Ar s2 based on the ASCII value of their characters. t Ar n1 Fl eq Ar n2 True if the integers .Ar n1 and .Ar n2 are algebraically equal. t Ar n1 Fl ne Ar n2 True if the integers .Ar n1 and .Ar n2 are not algebraically equal. t Ar n1 Fl gt Ar n2 True if the integer .Ar n1 is algebraically greater than the integer .Ar n2 . t Ar n1 Fl ge Ar n2 True if the integer .Ar n1 is algebraically greater than or equal to the integer .Ar n2 . t Ar n1 Fl lt Ar n2 True if the integer .Ar n1 is algebraically less than the integer .Ar n2 . t Ar n1 Fl le Ar n2 True if the integer .Ar n1 is algebraically less than or equal to the integer .Ar n2 . .El
p These primaries can be combined with the following operators: l -tag -width Ar t Cm ! Ar expression True if .Ar expression is false. t Ar expression1 Fl a Ar expression2 True if both .Ar expression1 and .Ar expression2 are true. t Ar expression1 Fl o Ar expression2 True if either .Ar expression1 or .Ar expression2 is true. t Cm ( Ar expression Cm ) True if .Ar expression is true. .El
p The .Fl a operator has higher precedence than the .Fl o operator.
p Note that all file tests with the exception of .Fl h and .Fl L follow symbolic links and thus evaluate the test for the file pointed at. .Sh EXIT STATUS The .Nm utility exits with one of the following values: l -tag -width Ds t 0 .Ar expression evaluated to true. t 1 .Ar expression evaluated to false or was missing. t >1 An error occurred. .El .Sh STANDARDS The .Nm utility implements a superset of the .St -p1003.2 specification. .Sh HISTORY A .Nm utility appeared in .At v7 . .Sh CAVEATS The .Nm grammar is inherently ambiguous. In order to assure a degree of consistency, the cases described in .St -p1003.2 section 4.62.4, are evaluated consistently according to the rules specified in the standards document. All other cases are subject to the ambiguity in the command semantics.
p This means that .Nm should not be used with more than 4 operands (where the terminating .Cm ] in the case of the .Nm [ command does not count as an operand,) and that the obsolete .Fl a and .Fl o options should not be used. Instead invoke .Nm multiple times connected by the .Dq && and .Dq || operators from .Xr sh 1 . When those operators are not used, there is no need for the parentheses as grouping symbols, so those should also be avoided. Using .Xr sh 1 Ns 's .Cm ! command instead of the equivalent operator from .Nm can also protect the script from future test enhancements.
p Most expressions with 3 or less operands will evaluate as expected, though be aware that with 3 operands, if the second is a known binary operator, that is always evaluated, regardless of what the other operands might suggest had been intended. If, and only if, the middle operand is not a defined binary operator is the first operand examined to see if it is .Cm ! in which case the remaining operands are evaluated as a two operand test, and the result inverted. The only other defined three operand case is the meaningless degenerate case where parentheses (1st and 3rd operands) surround a one operand expression.
p With 4 operands there are just two defined cases, the first where the first operand is .Cm ! in which case the result of the three operand test on the remaining operands is inverted, and the second is similar to the 3 operand case, the degenerate case of parentheses surrounding an (in this case) 2 operand test expression.