Solaris Admin Series, part 9. Previous: The Solaris PATH Problem: /usr/bin vs /usr/xpg4/bin vs /usr/sfw/bin vs /usr/gnu/bin. Related: part 6, Shells on Solaris 10 and 11, and part 7, Solaris Man Pages. Next up: basic process management with ps -ef, pgrep, pkill, kill signals and nohup.
The day you really need a text editor on Solaris is rarely a good day. The box is in single-user mode because /etc/vfstab has a typo, you are on a serial console through an ILOM or a terminal server, the TERM variable says something the system has never heard of, and there is no vim or nano on a minimal install. What is always there is the traditional vi and, underneath it, the line editors ex and ed. This post covers what ships on each release, how to fix the terminal so vi works, the vi commands an admin actually uses, and how to make a clean recovery edit with ed when full-screen editing is impossible.
Applies to: both Solaris 10 and Solaris 11 (11.4), SPARC and x86. Differences called out below: on both releases /usr/bin/vi is the classic Sun (Bill Joy derived) vi, not vim, and /usr/xpg4/bin/vi is the XPG4/POSIX-conforming variant. Solaris 10 has no vim in the base OS (it came on the Companion CD or from OpenCSW); Solaris 11 offers vim (and nano) as optional IPS packages that may not be on a minimal or text-only install. ed and ex are part of the core OS on both, and terminal descriptions live in /usr/share/lib/terminfo on both.
Prerequisites
- A shell on a Solaris 10 or Solaris 11.4 system: console, serial console (ILOM/ALOM/terminal server) or SSH.
- Root, a role, or an RBAC profile allowing the file edits you need (on Solaris 11, root is a role by default; see the
pfeditnote below). - Knowing which shell you are in (part 6), because the syntax for setting
TERMdiffers between Bourne/ksh/bash and csh.
Step 1: Know what editors ship by default
| Editor | Solaris 10 | Solaris 11.4 | Needs a working TERM? |
|---|---|---|---|
/usr/bin/vi (also view, vedit, ex, edit) | Yes, core OS | Yes, installed by default | vi yes; ex no |
/usr/xpg4/bin/vi, /usr/xpg4/bin/ex | Yes (XPG4 package) | Yes | Same as above |
/usr/bin/ed, red (restricted ed) | Yes, core OS | Yes, core OS | No, works on any terminal |
vim | Not in base OS (Companion CD /opt/sfw or OpenCSW /opt/csw) | Optional IPS package (editor/vim), not always installed | Yes |
nano, GNU emacs | Not in base OS | Optional IPS packages | Yes |
dtpad (CDE), gedit (GNOME) | dtpad with CDE | gedit with the desktop group | GUI only, useless on a console |
$ ls -l /usr/bin/vi /usr/bin/ex /usr/bin/view /usr/bin/ed /usr/xpg4/bin/vi
$ type vi vim nano ed
# Solaris 11: which package delivers it, and is vim available?
$ pkg search -l /usr/bin/vi
$ pkg list -a 'editor/*'
# pkg install editor/vim # optional, needs a configured publisher
# Solaris 10: which package delivers it?
# pkgchk -l -p /usr/bin/vi
vi, ex and view are the same program started in different modes (view is read-only vi). On Solaris 10 they are hard links to one binary; on 11.4 you may see symlinks. Either way, learning plain vi means you can edit on every Solaris box you will ever touch, including the miniroot used for failsafe boots and install media.
Step 2: Fix TERM and terminfo first
Full-screen vi needs a terminal description from the terminfo database so it knows how to move the cursor and clear the screen. If TERM is unset, wrong, or names an entry that does not exist on this system, vi falls back to “open mode” (one line at a time) or draws garbage. Typical symptoms:
$ vi /etc/hosts
xterm-256color: Unknown terminal type
I don't know what kind of terminal you are on - all I have is 'xterm-256color'.
[Using open mode]
"/etc/hosts" 12 lines, 311 characters
Check what you have and whether terminfo knows it. Compiled entries live under /usr/share/lib/terminfo/<first letter>/<name> on both releases (Solaris 11 also has an ncurses database under /usr/gnu/share/terminfo that GNU programs use, which is why vim may work where /usr/bin/vi does not).
$ echo $TERM
xterm-256color
$ ls /usr/share/lib/terminfo/x/ | head
$ ls -l /usr/share/lib/terminfo/v/vt100 /usr/share/lib/terminfo/s/sun
$ infocmp xterm-256color > /dev/null || echo "no terminfo entry for $TERM"
$ tput cols; tput lines
80
24
Then set a TERM that exists. Good, safe choices:
| Where you are | TERM to use |
|---|---|
| SSH from a Linux or macOS terminal (xterm, GNOME Terminal, iTerm2, PuTTY) | xterm (use vt100 if xterm misbehaves) |
| SPARC framebuffer console | sun (or sun-color) |
| x86 text console | sun-color (Solaris 10 x86 and Solaris 11 x86 default) |
| Serial console via ILOM, ALOM, LOM or a terminal server | vt100 |
| Anything you are not sure about, or a dumb terminal | vt100, or give up on vi and use ed (Step 4) |
# sh, ksh, bash
$ TERM=vt100; export TERM
# csh, tcsh
% setenv TERM vt100
# Window size wrong after the change (lines wrap or the screen is cut off)?
$ stty rows 24 columns 80
$ stty -a | head -2
To make the serial console default stick, Solaris uses the console-login SMF service: on Solaris 10 and 11, svccfg -s svc:/system/console-login setprop ttymon/terminal_type = astring: vt100, then svcadm refresh svc:/system/console-login:default and svcadm restart svc:/system/console-login:default. For SSH sessions, set TERM in the client or in your ~/.profile with a guard such as infocmp "$TERM" >/dev/null 2>&1 || TERM=vt100.
Step 3: vi essentials every Solaris admin needs
Classic vi has two main modes: command mode (where you start, and where letters are commands) and insert mode (where letters are text). Esc always takes you back to command mode; if you are lost, press Esc twice. Lines starting with : are ex commands typed on the bottom line.
Getting in and out
| Keys | What it does |
|---|---|
vi file, view file | Edit a file; open read-only |
:w | Write (save) |
:q | Quit (refuses if there are unsaved changes) |
:wq, :x, ZZ | Write and quit (:x/ZZ only write if changed) |
:q! | Quit and throw away changes |
:w! | Force a write to a read-only file you own or as root |
:e! | Discard changes and reload the file from disk |
:w /tmp/copy | Write to a different file (handy when the original cannot be written) |
Inserting text
| Keys | Enters insert mode… |
|---|---|
i / a | before / after the cursor |
I / A | at the start / end of the line |
o / O | on a new line below / above |
rx | (not insert mode) replace one character with x |
cw, C | change to end of word; change to end of line |
Esc | back to command mode |
Moving and searching
| Keys | Movement |
|---|---|
h j k l | left, down, up, right (use these when arrow keys print A/B/C/D) |
w, b, 0, $ | next word, previous word, start of line, end of line |
G, 1G, 42G or :42 | last line, first line, line 42 |
Ctrl-F, Ctrl-B | page forward, page back |
/pattern, ?pattern | search forward, backward |
n, N | repeat search in the same, opposite direction |
Deleting, copying, undo
| Keys | Action |
|---|---|
x | delete character |
dd, 5dd, dw, D | delete line, 5 lines, word, to end of line |
yy, 5yy | yank (copy) line, 5 lines |
p, P | put after, before the cursor |
u | undo the last change (classic vi has one level; u again redoes it) |
U | undo all changes on the current line |
. | repeat the last change |
J | join next line onto this one |
ex commands worth memorizing
:set number " show line numbers (:set nonumber to turn off)
:set list " show tabs as ^I and line ends as $ (find stray whitespace, ^M)
:set showmode " show INSERT MODE on the status line
:set ic " ignore case in searches
:%s/old/new/g " replace everywhere
:10,20s/^/#/ " comment out lines 10-20
:g/^#/d " delete every comment line
:r /etc/hosts " read a file in below the cursor
:r !uname -a " read a command's output in below the cursor
:!ls -l /etc/vfstab " run a shell command, then return
:%!sort " filter the whole buffer through sort
Put favorite settings in ~/.exrc (or the EXINIT variable). Keep it to options classic vi understands, for example set showmode number. A .vimrc-style line in .exrc makes Solaris vi print an error every time it starts.
Editing system files as root, safely
# cp -p /etc/vfstab /etc/vfstab.$(date +%Y%m%d) # keep a dated copy, -p preserves mode/owner/time
# vi /etc/vfstab
# ls -l /etc/vfstab /etc/vfstab.20261107
-rw-r--r-- 1 root sys 542 Nov 7 14:20 /etc/vfstab
-rw-r--r-- 1 root sys 531 Nov 2 09:12 /etc/vfstab.20261107
vi and ed rewrite the existing file in place, so owner, group, mode and hard links are preserved. That is not true of “edit a copy then mv it over the original”, which leaves the new file owned by whoever made it; use cp back over the original, or fix ownership with chown/chmod afterwards. Many files under /etc are mode 0444 or 0644 owned by root; as root you need :w! for the read-only ones.
On Solaris 11, prefer pfedit for delegated edits: an RBAC authorization such as solaris.admin.edit/etc/hosts lets a non-root user run pfedit /etc/hosts, which opens a copy in $EDITOR, writes it back preserving ownership and logs the change through auditing. On Solaris 10, the equivalent is a role or sudoedit if sudo is installed.
Recovering after a crash or a dropped session
$ vi -r # list files that can be recovered
/var/tmp:
No files saved.
/var/preserve/root:
On Sat Nov 7 14:02:11 2026 saved 3 lines of about 2 words of file /etc/hosts
$ vi -r /etc/hosts # recover; check it, then :w and :q
$ ex -r /etc/hosts # same thing without full-screen mode
vi keeps its working buffer in /var/tmp (files named Ex…); preserved copies go under /var/preserve. Recovered text is your unsaved work, not the file on disk, so compare before writing.
Step 4: Use ed when nothing else works
ed is a line editor: it never needs cursor addressing, so it works with a broken TERM, on a dumb serial line, through a flaky out-of-band console, inside a script, and in the restricted environments you hit during recovery. It is also terse: it prints a byte count when it reads or writes and a single ? on any error. Type h to explain the last error or H to turn on verbose errors for the session, and use -p to get a prompt.
| Command | Meaning |
|---|---|
ed -p "*" file | Edit file with * as the prompt |
1,$p or ,p | Print all lines; ,n prints them with line numbers |
5p, 5,10n | Print line 5; lines 5 to 10 numbered |
/pattern/, ?pattern? | Go to next / previous line matching and print it |
a, i, c | Append after, insert before, change the current line; type text, end with a line holding only . |
d, 5,7d | Delete current line, lines 5 to 7 |
s/old/new/, s/old/new/gp | Substitute on the current line (and print it) |
g/re/p, g/re/s/a/b/ | Run a command on every line matching re |
u | Undo the last command |
w, q, Q | Write; quit (warns once if unsaved); quit without saving |
!cmd | Run a shell command |
Recovery example: comment out a bad line in /etc/vfstab
Solaris 10 with a UFS root drops to single-user mode (or a maintenance shell) when a vfstab entry cannot be mounted. Root is often mounted read-only at that point, so remount it first, then fix the file:
# mount -o remount,rw / # Solaris 10 UFS root; ZFS root (11) is normally already rw
# TERM=dumb; export TERM # we are not going to use vi anyway
# ed -p '* ' /etc/vfstab
542
* ,n
1 #device device mount FS fsck mount mount
2 #to mount to fsck point type pass at boot options
...
9 /dev/dsk/c1t1d0s6 /dev/rdsk/c1t1d0s6 /u01 ufs 2 yes -
* 9s/^/#/p
#/dev/dsk/c1t1d0s6 /dev/rdsk/c1t1d0s6 /u01 ufs 2 yes -
* w
543
* q
# mountall -l
The byte count went up by exactly one, which is a quick sanity check that you changed only what you meant to. Solaris vfstab fields are whitespace separated, so a tab versus spaces does not matter, but each entry must stay on one line with all seven fields.
Recovery example: back out a bad tunable in /etc/system
A wrong line in /etc/system can stop the kernel from booting. Boot with the old file (boot -a on SPARC or the GRUB -a kernel option on x86, and answer /dev/null or /etc/system.bak at the “Name of system file” prompt), or boot failsafe / a boot environment, then comment the line out. Comments in /etc/system start with *:
# ed /etc/system
2847
/zfs_arc_max/
set zfs:zfs_arc_max=0x10000000
s/^/* /p
* set zfs:zfs_arc_max=0x10000000
w
2849
q
On Solaris 11.4, Oracle recommends putting your own tunables in a file under /etc/system.d/ rather than editing /etc/system directly; the same ed technique works on those files.
Appending a line and editing from a script
# ed -s /etc/hosts <<'EOF'
$a
192.0.2.50 dbhost01 dbhost01.example.com
.
w
q
EOF
# tail -1 /etc/hosts
192.0.2.50 dbhost01 dbhost01.example.com
ed -s suppresses the byte counts, which makes ed a dependable in-place editor in scripts on Solaris 10, where no sed has -i (see part 8).
ex: vi’s own line mode
If vi drops you into open mode, or you started ex on purpose, you have the same commands as ed with the vi conveniences (:set number, % for all lines). Type vi at the : prompt to switch into full-screen mode once TERM is fixed, and Q in vi to drop back to ex. Accidentally pressing Q is a classic way to “lose” vi; type vi and press Enter to get it back.
Step 5: Set EDITOR and VISUAL
Several Solaris commands open an editor for you and pick it from VISUAL or EDITOR. If neither is set, the fallback is often ed, which is why crontab -e famously answers with nothing but a number: that is ed printing the byte count of your crontab. Type q to leave it.
# ~/.profile (sh, ksh, bash)
EDITOR=/usr/bin/vi; VISUAL=/usr/bin/vi; export EDITOR VISUAL
# ~/.cshrc (csh)
setenv EDITOR /usr/bin/vi
setenv VISUAL /usr/bin/vi
$ crontab -e # now opens vi
# svccfg -s svc:/site/myapp editprop # Solaris 11: edit service properties in $EDITOR
# visudo # if sudo is installed
Set root’s editor too, and keep it the absolute path /usr/bin/vi rather than vim, so it still works when /usr/gnu/bin or an optional package is missing.
Verification
$ echo $TERM; infocmp $TERM > /dev/null && echo "terminfo OK"
$ tput cols; tput lines # should match your window
$ echo $EDITOR $VISUAL
$ vi /tmp/vitest # o, type a line, Esc, :wq
$ ed -s /tmp/vitest <<'EOF'
,p
q
EOF
$ ls -l /etc/vfstab /etc/system # owner/mode unchanged after edits
After any recovery edit to /etc/vfstab, run mountall -l (or mount -a-style checks with mount -v) before rebooting; after an /etc/system change, keep the backup copy until the next clean boot.
Troubleshooting and gotchas
- “Unknown terminal type” or open mode.
TERMnames an entry missing from/usr/share/lib/terminfo(common withxterm-256color,screen-256color,tmux-256coloron older releases). SetTERM=xtermorvt100. - Arrow keys type A, B, C, D or the screen redraws oddly. Still a TERM mismatch, or you are in insert mode. Use
h j k l, or fix TERM. - Screen size wrong on a serial console. Serial lines do not report window size; set it with
stty rows 24 columns 80to match your emulator. - “File is read only”. Use
:w!as root, or check whether the file system is mounted read-only (mount -v | grep " / ") or immutable inside a Solaris 11 immutable zone. - “Tmp file too large” or vi cannot start on huge files. Classic
viworks through/var/tmp; if it is full or the file is enormous, view it withmore/tail, or edit withed/sedto a new file. Point the temp directory elsewhere with:set directory=/bigfsinEXINIT. - Stale recovery files. Old preserved buffers accumulate under
/var/preserveand/var/tmp/Ex*; list them withvi -rand remove the ones you do not need. - ^M at the end of every line. The file came from Windows. Check with
:set listorcat -v, then convert:dos2unix file.win file.unix, or invi:%s/Ctrl-VCtrl-M$//. A CR in/etc/vfstab, a script shebang or a crontab line causes baffling failures. - Linux vim muscle memory. Classic Solaris
vihas no visual mode (v), no multi-level undo orCtrl-Rredo, no syntax highlighting, and no:set paste. Pasting with autoindent on stair-steps text; use:set noaibefore pasting. - vim installed on Solaris 11 but vi is not vim.
/usr/bin/vistays the classic editor. Runvimexplicitly or alias it; do not replace/usr/bin/vi, which package updates restore. - Sparse-root zones on Solaris 10.
/usris shared read-only from the global zone, soviandedare always there, but you cannot addviminside the zone into/usr; install add-ons in the global zone or under/opt. - Separate /usr not mounted in early single-user. On old Solaris 10 layouts with
/usron its own slice, editors under/usr/binare missing until you mount it (mount /usr). Booting failsafe or from media gives you a miniroot withvianded; mount the real root on/aand edit/a/etc/vfstab.
What’s next in the Solaris Admin Series
Next up is basic process management on Solaris 10 and 11: ps -ef, pgrep, pkill, kill signals and nohup. Catch up with part 8, The Solaris PATH Problem, part 7, Solaris Man Pages, part 6, Shells on Solaris 10 and 11, and part 3, Solaris Filesystem Layout Tour.
Official references: vi(1), ex(1), ed(1), terminfo(5), tput(1), infocmp(1), crontab(1) and pfedit(8) in the Oracle Solaris 11.4 Reference Library, and vi(1), ed(1), terminfo(4) and crontab(1) in the Oracle Solaris 10 1/13 Information Library.
