expr(1) on Solnix vs Linux and the BSDs

On Solnix, expr is the illumos /usr/bin/expr. It has three variants that differ in output and in what the : operator counts. The most important difference for Linux and BSD users is that length, substr and index are documented only as x86-only compatibility operators, and there is no match keyword or + TOKEN escape.

What Solnix runs

A default Solnix system runs the illumos /usr/bin/expr. /usr/xpg4/bin/expr and /usr/xpg6/bin/expr are also shipped. /usr/bin/expr and xpg4 write nothing for a null string, while xpg6 always ends the output with a newline. The : operator counts bytes in /usr/bin/expr and characters in xpg4. /usr/ucb/expr is listed as shipped, but the bundle does not describe it.

Differences

Compared withTopicWhat differs
all fouroutput for null resultSolnix /usr/bin/expr and /usr/xpg4/bin/expr write 0 for a zero value and nothing at all for a null string. /usr/xpg6/bin/expr always ends output with a newline, even with no result. The counterpart pages do not say what they print for a null string.
Source: Solnix expr(1) DESCRIPTION (/usr/bin/expr, /usr/xpg4/bin/expr; /usr/xpg6/bin/expr); Linux/FreeBSD/OpenBSD/NetBSD expr(1) DESCRIPTION
all fourbytes vs characters for :Solnix /usr/bin/expr returns the number of bytes matched by the : operator. Solnix /usr/xpg4/bin/expr returns characters. Linux and the three BSD pages say characters. In multibyte locales, /usr/bin/expr can give a different count.
Source: Solnix expr(1) OPERANDS (expr : expr); Linux expr(1) (STRING : REGEXP); FreeBSD/OpenBSD/NetBSD expr(1) expr1 : expr2
Linuxstring keywordsSolnix documents index, length and substr only as 'Compatibility Operators (x86 only)', and they count bytes. There is no match keyword and no + TOKEN escape. Linux documents match, substr, index, length and + TOKEN as ordinary expressions.
Source: Solnix expr(1) Compatibility Operators (x86 only); Linux expr(1) match, substr, index, length, + TOKEN
FreeBSD, OpenBSD, NetBSDstring keywords on the BSDsFreeBSD treats length, substr, index and match as plain strings. OpenBSD documents no such keywords. NetBSD documents only length (bytes), which it calls a GNU-compatibility extension. Solnix documents index, length and substr, but only as x86 compatibility operators.
Source: FreeBSD expr(1) STANDARDS; OpenBSD expr(1) DESCRIPTION; NetBSD expr(1) length, STANDARDS; Solnix expr(1) Compatibility Operators
Linuxexit status 3Solnix documents exit status >2 for any error. Linux documents exactly 3. A Linux script that tests for 3 explicitly should test for a value above 2 on Solnix.
Source: Solnix expr(1) EXIT STATUS (>2); Linux expr(1) DESCRIPTION (exit status)
FreeBSDexit status above 2FreeBSD documents only exit statuses 0, 1 and 2. Solnix, OpenBSD and NetBSD also document >2 for errors such as memory allocation failure. Overflow on FreeBSD ends the program with an error status, but the number is not given.
Source: FreeBSD expr(1) EXIT STATUS, DESCRIPTION (overflow); Solnix expr(1) EXIT STATUS
FreeBSD-e option, EXPR_COMPAT and leading minusFreeBSD has -e and the EXPR_COMPAT variable, and treats a leading argument starting with a minus as an option unless compat mode is on. The Solnix page documents no options, no EXPR_COMPAT and no -- handling.
Source: FreeBSD expr(1) SYNOPSIS, -e, ENVIRONMENT, Compatibility with previous implementations; Solnix expr(1) SYNOPSIS
LinuxoptionsLinux expr accepts --help and --version. The Solnix page documents no options, only argument operands.
Source: Linux expr(1) SYNOPSIS, --help, --version; Solnix expr(1) SYNOPSIS
Linux, FreeBSD, NetBSDoperand that looks like an operatorOn Solnix, a variable that expands to an operator such as = is read as the operator. The page's workaround is to prefix both sides with a letter: expr X$a = X=. Linux has the + TOKEN form. FreeBSD says such an operand is a syntax error. NetBSD says it handles / and -- by context.
Source: Solnix expr(1) NOTES; Linux expr(1) + TOKEN; FreeBSD expr(1) DESCRIPTION; NetBSD expr(1) COMPATIBILITY
FreeBSD, NetBSDinteger range and overflowFreeBSD uses intmax_t arithmetic and NetBSD uses 64-bit integers, and both check for overflow. The Solnix page does not state an integer range or overflow behaviour.
Source: FreeBSD expr(1) DESCRIPTION; NetBSD expr(1) COMPATIBILITY; Solnix expr(1) OPERANDS
all fourexpression length limit and blanksThe Solnix page says terms must be separated by blanks and the expression is limited to LINE_MAX (2048 characters). None of the counterpart pages state such a limit.
Source: Solnix expr(1) OPERANDS; Linux/FreeBSD/OpenBSD/NetBSD expr(1) DESCRIPTION
FreeBSD, OpenBSD, NetBSDfailed match with a subexpressionThe BSD pages say a failed match returns the null string when the pattern has a \(...\) subexpression, and 0 otherwise. The Solnix page says only that the operator returns 0 on failure, and \1 when a subexpression exists.
Source: FreeBSD/OpenBSD/NetBSD expr(1) expr1 : expr2; Solnix expr(1) OPERANDS (expr : expr)

Standards

  • POSIX: expr is a POSIX.1-2024 utility.
  • Solnix: Interface Stability: Standard. The ATTRIBUTES table also lists CSI as enabled.
  • FreeBSD: The expr utility conforms to IEEE Std 1003.2008 (“POSIX.1”), provided that backwards compatibility mode is not enabled. The -e flag is an extension.
  • OpenBSD: The expr utility is compliant with the IEEE Std 1003.1-2008 (“POSIX.1”) specification.
  • NetBSD: The expr utility conforms to IEEE Std 1003.2 (“POSIX.2”). The length keyword is an extension for compatibility with GNU expr.

Writing portable scripts

  • Use only the operators | & = > >= < <= != + - * / % and :, quoting those the shell treats specially. Avoid length, substr, index and match, which are x86-only on Solnix and undefined or missing on some BSDs.
  • Guard against operands that look like operators, for example expr X$a = Xvalue. Do not rely on a leading minus or a bare -- as the first argument.
  • Treat any exit status above 1 as failure instead of testing for 2 or 3, because Linux uses 3 and Solnix uses >2 for errors.

Every difference here is taken from the manual pages linked above: Solnix's published page, Linux (man-pages and the GNU and util-linux manuals), FreeBSD, OpenBSD and NetBSD. Each row names its source. Where a manual is silent, this page is too. Compiled 2026-10-26. Found a mistake? Mail hackers@lists.solnix.io.