TonicBoxOS · shell reference

sh - the shell

The TonicBoxOS command shell: a small POSIX-style sh with pipes, redirection, variables and expansions, command and arithmetic substitution, globbing, control flow, functions, aliases, and job control. It runs interactively in the terminal, executes scripts, and is the login shell that sources your profile.

pipes | ; && || redirect > >> < 2> 2>&1 &> flow if while for case jobs & fg bg
Survival kit
ls | grep err
pipe one command into the next
x=5; echo $x
set and expand a variable
for f in *.c; do ...
loop over a glob
cmd > out.txt
redirect output to a file
alias ll='ls -lp'
define a shortcut
Ctrl-Zfg
suspend, then resume a job

00Running

With no arguments sh is an interactive read-eval-print loop. It draws its own prompt - user@dev:~/path$ in green, or root@dev:...# in red when you are root - and ~ abbreviates your $HOME. It also runs non-interactively:

FormRuns
sh SCRIPT [args]a script file; $0 is the script, $1… the arguments
sh -c 'CMDS' [name [args]]a command string, with optional positional parameters
#!/bin/sha shebang script, run through the shell by the kernel

Started as a login shell (argv​[0] beginning with -), it first sources /etc/profile and then ~/.profile - that is where the default aliases and environment live.

Input can span several lines. If a line ends with a backslash (line continuation), inside an open quote, on a trailing |, && or ||, inside an unclosed if / while / for / case / { block, or right after a bare function head, the shell keeps reading until the command is complete.

01Builtins

These run inside the shell itself rather than as separate programs:

BuiltinEffect
cd [DIR]change directory; no argument goes to your home, - to the previous directory
exit [N]leave the shell with status N
break [N] / continue [N]exit or restart the enclosing loop (N levels)
return [N]return from a function with status N
shift [N]drop the first N positional parameters (default 1)
set [--] ARGSset the positional parameters
export NAME[=VAL]put a variable into the environment for child programs
unset NAMEremove a variable
read VARread one line of input into VAR (status 1 at end of input)
test EXPR / [ EXPR ]evaluate a condition (see below)
true / false / :do nothing, with status 0 / 1 / 0
. / source FILErun a file's commands in the current shell
alias / unaliasdefine, list, or remove aliases
umask [OCT]show or set the octal file-creation mask
jobs / fg / bgjob control (see below)

Anything else is resolved as an alias, then a builtin, then a function, then an external program (found via execvp on $PATH). test / [ understand -z / -n (empty / non-empty string), -e / -f / -d (path exists / is a file / is a directory), -r / -w / -x / -s (readable / writable / executable / non-empty), string = and !=, the integer comparisons -eq -ne -lt -le -gt -ge, ! EXPR (negate), -a / -o (and / or), and a bare STRING (true when non-empty).

02Variables

NAME=VALUE (no spaces around =) sets a shell variable; $NAME or ${NAME} expands it, and an undefined name expands to nothing. Shell-local variables shadow the environment; export pushes one into the environment so child programs inherit it, and an exported name is kept in sync.

ParameterExpands to
$?exit status of the last command
$0$9positional parameters (script name / arguments)
$#number of positional parameters
$@ / $*all positional parameters, space-separated
$$ / $!shell PID / PID of the last background command
$ name=world
$ echo "hello, $name (last status $?)"
hello, world (last status 0)

03Expansions

Quoting. 'single quotes' are fully literal - nothing inside expands, not even a backslash. "double quotes" keep spaces as one word but still expand $; inside them a backslash escapes only $, \, ", `, and a newline. Outside quotes a backslash escapes the next character - \ is a literal space, \$ a literal dollar - and a backslash at the end of a line continues the command onto the next line.

ExpansionDoes
$(command) / `command`substitutes the command's output (trailing newlines trimmed); may contain pipes and functions
$(( expr ))integer arithmetic (arithmetic operator set as in Limits)
${NAME:-w} / := / :+default, assign-default, or alternate value
${#NAME}length of the value
${NAME#pat} / ## / % / %%strip a matching prefix or suffix
* / ? / [...]glob: any run, a single character, or a character class
$ echo "there are $(ls *.c | wc -l) sources"
$ echo $(( (3 + 4) * 2 ))
14

A glob that matches nothing is left untouched, so the literal pattern is passed through.

04Pipes & redirection

OperatorEffect
a | bpipe a's output into b; stages run concurrently
a ; brun a, then b
a && brun b only if a succeeded
a || brun b only if a failed
cmd > f / >> fsend stdout to a file (truncate / append)
cmd < fread stdin from a file
cmd 2> fsend stderr to a file; any descriptor works with N> f
cmd > f 2>&1send stderr wherever stdout currently points; redirections apply left to right
cmd &> fsend both stdout and stderr to a file
cmd >&- / <> fclose a descriptor; open a file for read-write
cmd &run in the background

Pipelines are real forked processes joined by pipes, so a reader that exits early terminates the writer - yes | head stops cleanly. A background command prints [bg] PID and is announced as [done] PID at the next prompt.

05Control flow

if test -f config; then
  echo found
elif test -d config; then
  echo a directory
else
  echo missing
fi

while read line; do echo "$line"; done < file

for f in *.c; do echo "$f"; done

case "$answer" in
  y|yes) echo ok ;;
  *)     echo no ;;
esac

A command is "true" when its exit status is 0. until is while with the condition negated. case patterns are globs and may list alternatives separated by |; the first matching branch runs.

06Functions & aliases

A function groups commands under a name. Inside it, $1, $2… are the arguments passed to the call and $# their count.

$ greet() { echo "hi, $1"; }
$ greet world
hi, world

An alias is a shortcut expanded before the command runs. alias name='value' defines one, alias with no arguments lists them, and unalias name removes one. Expansion is recursive but loop-safe - an alias can refer to a command of the same name without recursing forever. The default aliases (ll, la, .., …) are defined in /etc/profile.

07Jobs

Job control is active only when a real interactive terminal is attached (piped or headless input runs the shell as a plain non-interactive loop with no job control).

ActionEffect
cmd &start a job in the background
Ctrl-Zsuspend the foreground job ([N]+ Stopped)
jobslist active jobs
fg [N]resume a job in the foreground
bg [N]resume a suspended job in the background

08Limits