Frank Schacherer Homepage
home technology bibliography

Unix /bin/sh Refcard


Since /bin/sh is available on every Unix system, it is the shell of choice for writing scripts, even while it has much less power than the other shells. Therefore it is a good idea to learn the basic syntax. while man sh will give you the full story, here are some of the most common constructs. Probably you'd be more portable by just learning perl and using that everywhere. The shell can be used interactively or as a script.

Flow control
for if
for var [in word-list]
if cmds
case while
case word in
  pattern1) cmds;;
  patternN) cmds;;
while cmds
What irks me most is the shitty syntax for conditions. Here my personal back-breakers:
  • conditions test expressions with the syntax [ expression ] (note the spaces inside the brackets!)
  • logical operators: and is -a, or is -o, not is !. All have to be set apart by space! Or can also be emulated by [ test1 ] || [ test2 ]
  • if [ ! -e file ])
  • operators for file tests: -r file (readable), -d file (directory), -e file (exists)
  • string comparisons:= (string equal), != (strings different). May not have space around them!
  • numeric comparisons:-eq (numbers equal). Note the string/number thing is the other way round than it is in Perl, also note the - in -eq
  • there must be a semicolon before the keyword that indicates the start of the dependent block, if both are on the same line: like if [ -e file -a -r file ]; then echo "Yep"; fi or for x in ABC*.txt; do sort $x; done
Your usual constructs, with fi etc instead of blocks. Cmds means a list of commands. Bracketed parts are optional. Keywords must start on a fresh line, or after a semicolon. Patterns can use filename expansion (without the exeptions), word is usally a variable. For without in uses the position parms. You can use continue and break with loops.

Each command can be given arguments during its invocation. It turns into a process, reads data from standard input, outputs results to standard output, errors to standard error. Upon finishing it returns an errorlevel into $?, which is 0 if successful, positive otherwise.
Any filename is possible, as long as the script has the magical #!/bin/sh as the first line. Conventional is
For mathematical expressions, use the expr command. Remember to escape special characters (like * for multiplication as \*).

Special characters and Names
I/O redirection
redirect input to handle
redirect output to handle
cmd>>file append to file
&0 handle for STDIN
&1 handle for STDOUT
&2 handle for STERR
redirect stream to stream
2>file redirect STDERR to file
>&2 redirect output to STDERR
2>&1 redirect STDERR to STDOUT
cmd1|cmd2 pipe output of cmd1 to input of cmd2

Regexen for filename expansion
any number of chars, exept leading . and /., /
one char
[ac-e] char a, c, d, or e.
[!ab] not char a or b

User-defined variables
To export variable names from the script to the environment use export (instead of setenv like in csh).
varname='value' Assignment of value to variable. No space around equals sign! The quotes are optional for simple words. varname= assigns "" (empty string). Example for settimg and exporting DISPLAY: DISPLAY=; export DISPLAY
$varname Using a variable.
${varname} Using a variable, braced form if end of varname is ambiguous. Is undef if no assignment happened.
${varname:-word} Using a variable, or word, if it is undef or empty.
${varname:=word} Using a variable, after assigning word, if it is undef or empty.
${varname/pattern/string} Replace pattern with string in the value of varname.

Automatic variables
$1 to $9 args (params) 1-9 for the script.
$0 the script name
$# number of parameters
$@ the list of all parameters as a list
$* the list of all parameters as one string
$? errorlevel of last command
$! PID of last background process
$$ PID of current process
'...' noninterpolated string
"..." $name, `cmd` and \ interpolated string
`cmd` command substitution replaces command with its output

# turns the rest of the line into a comment
cmd& run cmd in background
cmd1 && cmd2 cmd2 only executes, when cmd1 returns success
cmd1 || cmd2 cmd2 only executes, when cmd1 returns failure
\ Escape. Concatenates lines.

chmod 755 `find . -type d` change rights for dirs under .
rm `find . -name "*.html~"` remove all .html~ files in dir tree