Solaris Admin Series, part 8. Previous: Solaris Man Pages: Sections, man -k/-K, catman and the Oracle Documentation Library. Related: part 3, Solaris Filesystem Layout Tour, and part 6, Shells on Solaris 10 and 11. Next up: text editors on a bare system, vi essentials and ed when nothing else works.
Sooner or later every admin coming from Linux runs grep -q, id -u or sed -i on a Solaris box and gets an error, or worse, silently different behavior. The reason is that Solaris ships several versions of the same commands in different directories: the traditional Solaris (System V) tools in /usr/bin, POSIX/XPG-conforming versions in /usr/xpg4/bin and /usr/xpg6/bin, BSD versions in /usr/ucb, bundled freeware in /usr/sfw/bin on Solaris 10, and GNU versions in /usr/gnu/bin on Solaris 11. Which one runs depends entirely on the order of your PATH. This post explains what lives where, how to see which binary you are really getting, and how to set PATH for interactive users, root, cron and SMF so scripts behave the same everywhere.
Applies to: both Solaris 10 and Solaris 11 (11.4), SPARC and x86. The headline differences: Solaris 10 has /usr/sfw/bin (GNU and open-source extras such as gtar, ggrep, gmake, wget) and real tools in /usr/ccs/bin; Solaris 11 drops /usr/sfw, delivers GNU tools as IPS packages into /usr/gnu/bin (with g-prefixed names in /usr/bin), moves most of /usr/ccs/bin into /usr/bin, and modernizes many /usr/bin commands, so the gaps are smaller but not gone.
Prerequisites
- A shell on a Solaris 10 or Solaris 11.4 system (global zone or non-global zone).
- Root or a role with the Software Installation profile only if you want to add packages (for example the GNU tools on a minimal Solaris 11 install).
- Basic familiarity with ksh or bash; see part 6 for which shell you are actually running.
The directories and what is in them
| Directory | What it holds | Solaris 10 | Solaris 11.4 |
|---|---|---|---|
/usr/bin | Traditional Solaris (SVR4-derived) commands; the default behavior | Yes; many tools pre-POSIX (old awk, grep without -q/-E, id without -u) | Yes; many tools updated, plus g-prefixed GNU links (gtar, ggrep, gsed, gmake) |
/usr/xpg4/bin | POSIX.2 / XPG4 (SUSv1/v2) conforming versions | Yes, dozens of commands (grep, awk, sed, id, tr, sh, …) | Yes, kept for standards conformance |
/usr/xpg6/bin | SUSv3 (POSIX.1-2001) versions where they differ from XPG4 | Yes, a handful of commands | Yes, a handful of commands |
/usr/ucb | BSD-compatible commands (ps, ls, echo, ln, …) | Yes (SUNWscpu) | Optional package compatibility/ucb |
/usr/ccs/bin | C Compilation System: make, ar, ld, as, lex, yacc, dump | Yes, real binaries; not in default PATH | Mostly compatibility links; the tools live in /usr/bin |
/usr/sfw/bin | Sun Freeware companion bundle: gtar, ggrep, gmake, wget, openssl, gcc 3.4.3 | Yes | Gone |
/usr/gnu/bin | GNU versions under their plain names (grep, sed, tar, make, ls, find, …) | No | Yes, from packages such as text/gnu-grep, text/gnu-sed, archiver/gnu-tar, file/gnu-coreutils, file/gnu-findutils |
/usr/sbin, /sbin | System administration commands | Yes | Yes |
/opt/csw/bin, /opt/sfw/bin | Third-party packages (OpenCSW, Companion CD) | Common add-on | Rare; prefer IPS packages |
Remember from part 3 that /bin is a symlink to usr/bin on both releases, so /bin/grep and /usr/bin/grep are the same file.
Step 1: See your current PATH and what it resolves to
$ echo $PATH
/usr/bin:/usr/sbin
$ type grep awk sed tar
grep is /usr/bin/grep
awk is /usr/bin/awk
sed is /usr/bin/sed
tar is /usr/bin/tar
$ whence -v id # ksh / ksh93
id is /usr/bin/id
$ type -a grep # bash: every match in PATH order
grep is /usr/bin/grep
grep is /usr/xpg4/bin/grep
grep is /usr/gnu/bin/grep
Use type (all shells) or whence -v (ksh) rather than which. On Solaris, /usr/bin/which is a csh script that reads your ~/.cshrc, so it can report a different answer from the one your ksh or bash will actually run.
Step 2: See all the versions of a command on the system
$ ls -l /usr/bin/grep /usr/xpg4/bin/grep /usr/gnu/bin/grep /usr/sfw/bin/ggrep 2>/dev/null
# Which package delivers each one?
# Solaris 10 (SVR4):
# pkgchk -l -p /usr/xpg4/bin/grep
# pkgchk -l -p /usr/sfw/bin/ggrep
# Solaris 11 (IPS):
$ pkg search -l /usr/gnu/bin/grep
$ pkg contents -t link -o path,target -a path=usr/bin/ggrep text/gnu-grep
The first column of output tells you which directories exist on this box. On a minimal Solaris 11.4 install (solaris-minimal-server or solaris-small-server) the GNU tools may not be installed at all; pkg install text/gnu-grep text/gnu-sed archiver/gnu-tar file/gnu-coreutils file/gnu-findutils adds them.
Step 3: Know the classic behavior differences
These are the ones that break Linux-written scripts most often. They are worst on Solaris 10; on 11.4 several /usr/bin commands already accept the POSIX options, but check the man page for your SRU instead of assuming.
| Task | Solaris 10 /usr/bin | Portable fix |
|---|---|---|
Quiet match: grep -q | Not supported | /usr/xpg4/bin/grep -q, or grep pattern file >/dev/null |
Extended regex: grep -E | Not supported | /usr/bin/egrep or /usr/xpg4/bin/grep -E |
Numeric user ID: id -u | Not supported (prints usage) | /usr/xpg4/bin/id -u |
awk with functions, -v, getline var | /usr/bin/awk is the old 1977 awk | nawk or /usr/xpg4/bin/awk |
In-place edit: sed -i | Not supported (no Solaris sed has it) | Write to a temp file and mv, use perl -pi -e, or gsed -i on 11 |
Compressed tar: tar xzf | No z flag on Solaris 10 | gzip -dc f.tgz | tar xf -, or gtar xzf |
Epoch seconds: date +%s | Not supported | nawk 'BEGIN{srand(); print srand()}' or perl -e 'print time' |
Character ranges: tr a-z A-Z | Treats - literally unless bracketed | tr '[a-z]' '[A-Z]' or /usr/xpg4/bin/tr |
Full command lines in ps | ps -ef truncates args at 80 chars | /usr/ucb/ps -auxww or pargs PID |
$(...) and test -e in /bin/sh | Bourne shell rejects them | Use #!/bin/ksh or #!/usr/xpg4/bin/sh (see part 6) |
# Solaris 10 examples
$ /usr/bin/id -u
id: illegal option -- u
Usage: id [-ap] [user]
$ /usr/xpg4/bin/id -u
0
$ echo "a b" | /usr/bin/grep -q a
grep: illegal option -- q
Usage: grep -hblcnsviw pattern file . . .
$ echo "a b" | /usr/xpg4/bin/grep -q a && echo found
found
Step 4: Choose a PATH order on purpose
There is no single right order, only a deliberate one. Pick based on what the account is for:
| Goal | Suggested PATH | Notes |
|---|---|---|
| Native Solaris behavior (most admin accounts) | /usr/bin:/usr/sbin (+ /usr/sfw/bin at the end on S10) | What Oracle documentation and Solaris scripts assume. GNU tools reachable by g name. |
| POSIX/SUS conformance (portable scripts) | /usr/xpg6/bin:/usr/xpg4/bin:/usr/bin:/usr/sbin (+ /usr/ccs/bin on S10) | The order standards(5) on S10 / standards(7) on 11.4 recommends for SUSv3 applications. getconf PATH prints the system’s conforming PATH. |
| Linux-like interactive feel (Solaris 11 only) | /usr/gnu/bin:/usr/bin:/usr/sbin | Comfortable for people, risky for scripts: anything that parses ls, ps or df output may change. |
$ getconf PATH
# prints the PATH that finds the standards-conforming utilities on this release
Whatever you choose, keep /usr/gnu/bin out of root’s PATH, or at least after /usr/bin and /usr/sbin. Oracle’s own tools and SMF method scripts expect Solaris behavior, and a GNU tar or df in front of them is a classic source of odd failures.
Step 5: Set PATH in the right places
Interactive users
# ~/.profile (ksh, sh) or ~/.bash_profile (bash)
PATH=/usr/bin:/usr/sbin:/usr/sfw/bin # Solaris 10
PATH=/usr/bin:/usr/sbin # Solaris 11.4
export PATH
Neither release sets PATH in /etc/profile by default. New-user templates come from /etc/skel, so put your site default there before creating accounts. On Solaris 11, check what the installer wrote into the first user’s and root’s dotfiles; do not assume, just run echo $PATH after logging in.
Login and su defaults
When a user has no PATH in their dotfiles, login and su fall back to /etc/default/login and /etc/default/su. Both files use PATH for ordinary users and SUPATH for root:
# grep -E '^#?(PATH|SUPATH)=' /etc/default/login /etc/default/su
/etc/default/login:#PATH=/usr/bin:
/etc/default/login:#SUPATH=/usr/sbin:/usr/bin
/etc/default/su:#PATH=/usr/bin:
/etc/default/su:#SUPATH=/usr/sbin:/usr/bin
# Uncomment and edit to change the system default, for example:
PATH=/usr/bin:/usr/sbin
SUPATH=/usr/sbin:/usr/bin
su - builds a fresh environment and uses SUPATH before reading root’s profile; plain su keeps your current PATH, which is a common reason “the same command” behaves differently as root. On Solaris 11, root is a role by default, so this is the path you hit every time you su.
cron jobs
cron does not read your profile. It sets a minimal environment from /etc/default/cron (PATH for users, SUPATH for root, defaulting to roughly /usr/bin and /usr/sbin:/usr/bin). Either set PATH at the top of every script, or use full paths:
#!/bin/ksh
PATH=/usr/bin:/usr/sbin; export PATH
SMF method scripts
SMF starts methods with a small, clean environment. Set PATH inside the method script, or add it to the service’s method environment:
# svccfg -s svc:/site/myapp:default setenv -m start PATH /usr/bin:/usr/sbin
# svcadm refresh svc:/site/myapp:default
# svcprop -p start/environment svc:/site/myapp:default
sudo
If you use sudo (bundled on Solaris 11, an add-on on Solaris 10), it replaces PATH with its secure_path setting when one is configured. Check with sudo -V as root, or simply sudo sh -c 'echo $PATH'.
Step 6: Make scripts immune to PATH
The most reliable fix is not to depend on the caller’s PATH at all:
- Set PATH explicitly as the first line after the shebang in every production script.
- Call the specific version you need when it matters:
/usr/xpg4/bin/grep -q,/usr/bin/nawk,/usr/gnu/bin/sed -i. - On scripts that must run on both releases, test once and branch:
case $(uname -r) in 5.10) AWK=nawk ;; *) AWK=/usr/bin/awk ;; esac. - Prefer POSIX options that work in
/usr/xpg4/binon both releases over GNU-only options.
#!/bin/ksh
# portable-check.sh - behaves the same on Solaris 10 and 11.4
PATH=/usr/xpg4/bin:/usr/bin:/usr/sbin
export PATH
if id -u | grep -q '^0$'; then
echo "running as root"
fi
awk -v host="$(uname -n)" 'BEGIN { printf "host=%s\n", host }'
Verification
$ echo $PATH
$ for c in grep awk sed tar id make; do type $c; done
$ su - root -c 'echo $PATH' # what root gets after su -
$ crontab -l # confirm scripts set their own PATH
$ svcprop -p start/environment svc:/site/myapp:default
Run the portable script above as an ordinary user, as root and from cron; it should print the same thing in all three contexts.
Troubleshooting and gotchas
- “illegal option” errors almost always mean you got
/usr/binwhere the script expected XPG4 or GNU behavior. Runtype cmdin the failing context. - Works interactively, fails in cron. cron’s PATH is not yours. Log
echo $PATHfrom the job, then fix the script. - A trailing colon or empty entry in PATH means the current directory. The commented default
PATH=/usr/bin:in/etc/default/loginincludes it. Never put.or an empty entry in root’s PATH. - GNU first in PATH changes output. GNU
ls,dfandpsformat differently; monitoring scripts that parse columns can quietly break. - Same command name, different package on 11.4.
/usr/bin/gtarand/usr/gnu/bin/tarare the same GNU tar;/usr/bin/taris Solaris tar, which understands Solaris ACLs and extended attributes (tar -p,-@) differently. Use Solaristarorcpiowhen you need Solaris ACLs preserved. - Missing
/usr/sfw/binafter migrating a script from 10 to 11. Replace/usr/sfw/bin/gtarwith/usr/bin/gtar,/usr/sfw/bin/wgetwith/usr/bin/wget, and so on. - Make on Solaris 10.
makelives in/usr/ccs/bin, which is not in the default PATH; add it, or use/usr/sfw/bin/gmakefor GNU makefiles. - Non-global zones. Each zone has its own dotfiles and
/etc/defaultfiles; fixing PATH in the global zone changes nothing inside zones. On Solaris 10 sparse-root zones,/usris shared, so the same binaries exist but PATH is still per zone.
What’s next in the Solaris Admin Series
Next we cover text editors on a bare system: the vi essentials every Solaris admin needs, and ed for when the terminal type is broken or you are in single-user mode. Catch up with part 7, Solaris Man Pages, part 6, Shells on Solaris 10 and 11, and part 5, Solaris First-Day Commands.
Official references: standards(7), filesystem(7), login(1), su(8), cron(8) and pkg(1) in the Oracle Solaris 11.4 Reference Library, and standards(5), su(1M) and crontab(1) in the Oracle Solaris 10 1/13 Information Library.
