2023-02-27

shell programming intro

overview of the most useful features

what shell?

the shell command language of the portable operating system interface

short: posix shell, sh

bash/ksh/zsh are sh compatible shells

variables

definition

a=bc
a="bc d"

no space around =

substitution

a="echo test"
$a

-> echo test

"$a"

-> "echo test"

conditionals

conditions use the exit code of commands

if grep -Fq error development.log
then
  # code
elif test $? -eq 3
  # code
else
  # code
fi

"true" is a program that is usually installed

while true
do
  echo test
done

"for" automatically splits arguments after "in" at whitespace

for a in b c d e
do
  echo $a
done

one-liner

for a in *; do echo "$a"; done
while true; do echo test; done

special parameters

array of program arguments

$@

argument 1, 2, 3, ...

$1
$2
$3

last exit code

$?

number of program arguments

$#
  • command lists

  • ; ignore exit code
  • && continue if exit code is 0
  • || continue if exit code is not 0
cd /tmp && echo test || echo xy ; echo z

left associative. evaluated like this

((cd /tmp && echo test) || echo xy) ; echo z

program output redirection

  • >> append to existing file
  • > truncate or create file then write
  • | pipe between standard output and standard input
  • < read from file
cat filename | tail >> output-file

sub-routines

name() {
  # code ...
}

accessing arguments

name() {
  echo $@
}
name() {
  echo $1
}

note the always empty parentheses

usage

name 3 2 1

commands

operator argument ...

file as operator. executes a file

/usr/bin/echo test
./this_file
echo

the last one searches the file in directories listed in the environment variable $PATH

variable as operator

a=echo test
$a 3

sub-routine as operator

test() {
  tail > /tmp/output
}

cat filename | test
compress_javascript() {
  uglifyjs --compress --mangle $@
}

cat input.js | compress_javascript > output.js

$@ is used in this example to be able to possibly pass additional arguments to "uglifyjs"

subshells

evaluate shell code and get what would be written on standard output as a string

$()
$(code ...)
timestamp=$(date +%s)

example file

#!/bin/sh

# links config files to their destinations

install() {
  sources=$@
  cp --recursive --force --symbolic-link --verbose \
    --target-directory=/ $sources
}

if test $# -eq 0
then
  echo usage example: ./exe/install hostname
else
  install "$PWD/data/$1"/*
fi

explanations

  • #!/bin/sh is a so called hashbang that is used by the program execution system call to select a program to evaluate the file content with
  • # creates code comments that will be ignored until the end of the line
  • scripts should have a description at the top so that readers do not need to analyse the code to get an idea of what it is supposed to do
  • use long options like --option so that readers do not have to look up in man pages what single character flags like -s or combinations like -rsat stand for
  • the \ is used to escape a linebreak character and treat what follows on the next line as if being on the current line
  • for statements like "if", put "then" on the following line, to not have to add an extra semicolon like "if; then"
  • "test" is a program that is usually installed that is also aliased as [

to execute a file

./filename
sh filename