Shell scripting
edos-sh is the shell, installed as /bin/sh. It is a real scripting language rather
than a command dispatcher: functions, control flow, arithmetic, globbing, heredocs and
job control.
One thing separates it from POSIX sh on sight. Every block ends with end — there is
no fi, no done, no esac, and no then or do to open one either.
#!/bin/shfor file in $(ls /bin) if [ -f /bin/$file ] echo "program: $file" endendControl flow works in scripts, not interactively.
Running a script
Section titled “Running a script”sh script.sh # run a filesh script.sh a b c # with positional argumentssh -c "echo hello" # a single commandsh -e script.sh # exit on the first failure./script.sh # needs a #!/bin/sh lineVariables
Section titled “Variables”Assignment needs no keyword. export puts a variable in the environment children
inherit.
NAME=valueexport PATH=/binunset NAME$? |
exit status of the last command |
$0 |
script name, or sh when interactive |
$1–$9 |
positional arguments |
$# |
how many there are |
$@ |
all of them |
Double quotes expand, single quotes do not. ~ expands to $HOME.
echo "$HOME" # /echo '$HOME' # $HOMESubstitution
Section titled “Substitution”$(...) captures a command’s output, and nests.
FILES=$(ls /bin)echo "count: $(echo $(ls /bin | wc -w))"$(( ... )) evaluates integer arithmetic: + - * / %, comparisons < <= > >= == !=,
!, parentheses, and assignment. Variables inside need no $.
echo $(( (2 + 3) * 4 )) # 20i=0i=$(( i + 1 ))Conditions
Section titled “Conditions”test, also spelled [, sets the exit status. Any command works as a condition: zero is
true.
if [ -f /bin/sh ] echo existselif [ -d /bin ] echo directoryelse echo neitherend| Test | True when |
|---|---|
-f PATH |
a regular file |
-d PATH |
a directory |
-e PATH |
exists at all |
-z STR / -n STR |
empty / non-empty |
STR = STR / STR != STR |
strings match, or do not |
A -eq B |
also -ne, -lt, -gt, -le, -ge |
! EXPR |
negation |
With [, the brackets are arguments and need spaces around them.
while [ -f /tmp/lock ] sleep 1end
for f in one two three echo "item: $f"endbreak and continue do what they look like.
Functions
Section titled “Functions”function greet echo "hello, $1" return 0end
greet worldArguments arrive as $1–$9 and $@, the same as a script’s. return sets the exit
status and leaves the function.
Pipes, operators and redirection
Section titled “Pipes, operators and redirection”cmd1 && cmd2 # only if cmd1 succeededcmd1 || cmd2 # only if it failedcmd1 ; cmd2 # regardlessls /bin | grep shRedirection takes an explicit descriptor and can duplicate one onto another, per pipeline stage.
echo hi > file # truncateecho more >> file # appendcat < file # readcmd 2> errors # stderr to a filecmd 2>&1 # stderr onto stdoutcmd &> everything # bothHeredocs feed a block to stdin. Quoting the marker suppresses expansion.
cat > note << EOFhome is $HOMEEOF
cat << 'EOF'this $HOME stays literalEOFGlobbing
Section titled “Globbing”*, ? and [...] expand against the filesystem. A pattern matching nothing is passed
through unchanged rather than erroring, and a quoted one is left alone.
ls /bin/e*rm /tmp/*.logJob control
Section titled “Job control”Each pipeline gets its own process group, and the terminal is handed to whichever group
is in the foreground — which is why Ctrl+C on sleep 30 | cat kills both stages instead
of one.
sleep 60 & # backgroundjobs # what is running or suspendedfg 1 # bring it backbg 1 # resume it in the backgroundwait # block until children finishCtrl+Z suspends the foreground job.
Builtins
Section titled “Builtins”exit, help, pwd, cd, clear, echo, export, unset, env, history,
test, [, break, continue, set, return, kill, jobs, fg, bg, wait,
ifconfig, ip.
set -e exits on the first failure; set +e turns that back off.
A whole script
Section titled “A whole script”#!/bin/sh# greet.sh -- greet everyone named on the command line
set -e
if [ $# -eq 0 ] echo "usage: greet.sh NAME..." exit 1end
function greet echo "Hello, $1!"end
count=0for name in $@ greet $name count=$(( count + 1 ))end
echo "Greeted $count people."$ sh greet.sh Alice Bob CharlieHello, Alice!Hello, Bob!Hello, Charlie!Greeted 3 people.