tr(1) on Solnix vs Linux and the BSDs
On Solnix, tr is the illumos tr at /usr/bin/tr, and its man page describes a System V-style range syntax, [c-c], where Linux and the BSDs use c-c. The other big difference is that /usr/bin/tr does not list -C and leaves the result unspecified when string2 is shorter than string1, whereas Linux and the BSDs pad string2 with its last character.
The manual pages
- Solnix: tr(1) from
pkgs.solnix.illumos-world-man· illumos.org - Linux: tr(1) coreutils-full-9.11
- FreeBSD: tr(1) 15.1-RELEASE
- OpenBSD: tr(1) 8.0
- NetBSD: tr(1) 11.0
- Standard: POSIX.1-2024 (IEEE Std 1003.1-2024),
tr
What Solnix runs
A default Solnix system runs /usr/bin/tr (illumos). /usr/xpg4/bin/tr and /usr/xpg6/bin/tr are also shipped. The xpg4 synopsis has no -C and documents ranges as c-c. The xpg6 synopsis accepts [-c | -C]. /usr/ucb/tr is shipped too, but the bundle does not describe it. The -C option appears in the OPTIONS section, but only the xpg6 synopsis lists it, not the /usr/bin/tr synopsis.
Differences
| Compared with | Topic | What differs |
|---|---|---|
| all four | range syntax | The Solnix page documents the range construct as [c-c] for /usr/bin/tr and as c-c for /usr/xpg4/bin/tr. Linux, FreeBSD, OpenBSD and NetBSD document c-c (Linux: CHAR1-CHAR2). The Solnix text shown does not say how /usr/bin/tr treats a plain a-z.Source: Solnix tr(1) OPERANDS, /usr/xpg4/bin/tr c-c and /usr/bin/tr [c-c]; Linux tr(1) CHAR1-CHAR2; FreeBSD/OpenBSD/NetBSD tr(1) c-c |
| all four | string2 shorter than string1 | Solnix says the result is unspecified when string2 is shorter than string1. Linux, FreeBSD, OpenBSD and NetBSD all repeat the last character of string2 to fill the gap. Scripts that rely on this padding are not safe on Solnix. Source: Solnix tr(1) OPTIONS (When the -d option is not specified); Linux tr(1) DESCRIPTION (ARRAY2 is extended); FreeBSD/OpenBSD/NetBSD tr(1) DESCRIPTION |
| all four | -C and -c on /usr/bin/tr | The Solnix /usr/bin/tr synopsis is [-cds], without -C. -C is listed in OPTIONS and in the xpg6 synopsis. Linux, FreeBSD and OpenBSD synopses accept -C. NetBSD has only -c.Source: Solnix tr(1) SYNOPSIS, OPTIONS -C; Linux tr(1) -c, -C; FreeBSD/OpenBSD tr(1) SYNOPSIS; NetBSD tr(1) SYNOPSIS |
| Linux, FreeBSD, OpenBSD | -c versus -C meaning | Solnix -c complements by binary value (ascending). Solnix -C complements by character set and LC_COLLATE order. FreeBSD draws a similar distinction. On Linux and OpenBSD, -c and -C are the same, and OpenBSD says this is because tr is not locale-aware.Source: Solnix tr(1) OPTIONS -c, -C; FreeBSD tr(1) -C, -c; Linux tr(1) -c, -C, --complement; OpenBSD tr(1) -c, STANDARDS |
| Linux | GNU-only options and syntax | Linux tr (GNU coreutils) has -t/--truncate-set1, long options, --help and --version, the [CHAR*] and [CHAR*REPEAT] forms, and a \\ escape. The Solnix text shown has none of these. Do not use them in Solnix scripts.Source: Linux tr(1) -t, --truncate-set1, --help, --version, [CHAR*REPEAT], \\; Solnix tr(1) SYNOPSIS, OPERANDS |
| FreeBSD | -u unbuffered output | FreeBSD tr has -u to guarantee unbuffered output. The Solnix synopses have no -u.Source: FreeBSD tr(1) -u; Solnix tr(1) SYNOPSIS |
| FreeBSD, OpenBSD, NetBSD | repeat construct [#*n] | FreeBSD, OpenBSD and NetBSD document [#*n] for string2. OpenBSD and NetBSD tell portable scripts to use it instead of relying on last-character padding. The Solnix text in the bundle is trimmed and shows no equivalent. Source: FreeBSD/OpenBSD/NetBSD tr(1) [#*n]; OpenBSD tr(1) STANDARDS; NetBSD tr(1) STANDARDS |
| all four | -d with -s | On Solnix, using -d and -s together requires both string1 (to delete) and string2 (to squeeze), and the same string cannot serve both. FreeBSD, OpenBSD and NetBSD synopses show tr -ds string1 string2 as well. The Solnix page states the same-string restriction explicitly.Source: Solnix tr(1) OPTIONS (When the -d option is specified); FreeBSD/OpenBSD/NetBSD tr(1) SYNOPSIS |
| all four | character classes in string2 | On Solnix, string2 accepts only [:lower:] and [:upper:] (for case conversion), unless both -d and -s are given. The Linux, FreeBSD, OpenBSD and NetBSD texts shown do not state this restriction.Source: Solnix tr(1) OPERANDS [:class:]; Linux/FreeBSD/OpenBSD/NetBSD tr(1) [:class:] |
| FreeBSD | extra class names | FreeBSD lists the classes ideogram, phonogram, rune and special. The Solnix list is alnum, alpha, blank, cntrl, digit, graph, lower, print, punct, space, upper and xdigit, plus any class defined in LC_CTYPE. Source: FreeBSD tr(1) [:class:]; Solnix tr(1) OPERANDS [:class:] |
| FreeBSD, OpenBSD, NetBSD | NUL bytes and syntax checking | OpenBSD and NetBSD state that tr handles NUL bytes and rejects illegal syntax, for example -c or -s with one string and no other operands. The Solnix text shown says nothing about NULs; its /usr/bin/tr synopsis allows no operands or just string1.Source: OpenBSD tr(1) STANDARDS; NetBSD tr(1) COMPATIBILITY; Solnix tr(1) SYNOPSIS |
Standards
- POSIX: tr is a POSIX.1-2024 utility.
- OpenBSD: Compliant with the IEEE Std 1003.1-2008 (“POSIX.1”) specification, except that
-Cbehaves the same as-csince tr is not locale-aware. - NetBSD: Expected to be IEEE Std 1003.2 (“POSIX.2”) compatible.
- Solnix: The visible Solnix text does not include a standards section. It ships separate
/usr/xpg4/bin/trand/usr/xpg6/bin/trvariants.
Writing portable scripts
- Do not rely on string2 being padded when it is shorter than string1. Make string2 the same length as string1. Where string2 must be extended, use [#*n] only after testing, since the Solnix text shown does not document it.
- For case conversion, use tr '[:lower:]' '[:upper:]', which all five pages document. Avoid ranges such as a-z in scripts that must also run on Solnix
/usr/bin/tr, which documents [c-c].
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.