Chapter 10

John Backus famously observed about "changeable parts" and "framework":

"Let us distinguish two parts of a programming language. First, its framework which gives the overall rules of the system, and second, its changeable parts, whose existence is anticipated by the framework but whose particular behavior is not specified by it. For example, the for statement, and almost all other statements, are part of Algol's framework but library functions and user- defined procedures are changeable parts." (Link)

Frameworks in Bash

Alternation

Iteration

if/then/fi

WRONG!

$ if -f /etc/hosts 
> then
>  echo /etc/hosts
> fi
-f: command not found

if/then/fi

RIGHT!

$ if [ -f /etc/hosts ]
> then
>   echo /etc/hosts
> fi
/etc/hosts

Something other than test

$ if env > /dev/null
> then
>    echo true
> fi

if/then/else/fi

$ if touch /werwer 2> /dev/null
> then
>    echo created /werwer
> else
>    echo did not create /werwer
> fi
did not create /werwer

if/then/elif/then/else/fi

$ if touch /werwer 2> /dev/null
> then
>   echo created /werwer
> elif touch /tmp/werwer 2> /dev/null
> then
>   echo created /tmp/werwer
> else
>   echo cannot create any werwer
> fi
created /tmp/werwer

test syntax

Syntax Meaning
( EXP ) Expression is true
! EXP Expression is false
EXP1 -a EXP2 Logical and
EXP1 -o EXP2 Logical or
-n STR String has length > 0
-z STR String has length = 0
STR1 = STR2 Strings are equal
STR1 != STR2 Strings are not equal

test syntax

Syntax Meaning
INT1 -eq INT2 Integers are equal
INT1 -ge INT2 INT1 is greater or equal to INT2
INT1 -gt INT2 INT1 is greater than INT2
INT1 -le INT2 INT1 is less than or equal to INT2
INT1 -lt INT2 INT1 is less than INT2
INT1 -ne INT2 INT1 is not equal to INT2

test syntax

Syntax Meaning
FILE1 -ef FILE2 files have same device and inode number
FILE1 -nt FILE2 FILE1 is newer than FILE2
FILE1 -ot FILE2 FILE1 is older than FILE2
-d DIR DIR is an existing directory

test syntax

Syntax Meaning
-e FILE FILE exists
-f FILE FILE exists and is a regular file
-h FILE, -L FILE FILE exists and is a soft link
-r FILE FILE exists and is readable
-s FILE FILE exists and has a size > 0
-w FILE FILE exists and is writable
-x FILE FILE exists and is executable
-t FD FD r efers to a terminal device

for in

$ for name in !(*~)
> do
> echo $name
> done
01-introduction.tex
1.aux
1.html
1.log
1.nav
1.out
1.pdf

for without "in"

#!/bin/bash -x

# prints each command line argument

for name
do
  echo I found $name
done

Arithmetic with for (( ))

$ for((i=0; i<10; i++))
> do
>   echo $i
> done
0
1
2
3
4
5
6
7
8
9

while

$ while true
> do
>  echo 1
> done
1
1
1 [...]

until

until false
> do
> echo 1
> done
1
1
1

case

$ x=yellow
$ case $x in
>    green)
>      echo this is green
>      ;;
>    yellow)
>      echo this is yellow
>      ;;
>    esac
this is yellow

Positional parameters

Changing the arguments

$ cat ./simple-set.sh 
#!/bin/bash -x
echo Current params: $*
set `hostname`
echo Current params: $*
$ ./simple-set.sh a b c d e f
+ echo Current params: a b c d e f
Current params: a b c d e f
++ hostname
+ set linprog3
+ echo Current params: linprog3
Current params: linprog3

Shifting

$ set a b c d e f
$ echo $*
a b c d e f
$ shift
$ echo $*
b c d e f

"$*" versus "$@"

Counting parameters

$ set a b c d e f
$ echo $#
6
$ set "$*"
$ echo $#
1
$ set a b c d e f
$ set "$@"
$ echo $#
6

Other special variables

Environment variables

$ cat /proc/self/environ | tr '\0' '\n'

Environmental variables

$ cat /proc/self/environ  | tr '\0' '\n' | grep ALI
$ export ALIBABA=HOCUSPOCUS
$ cat /proc/self/environ  | tr '\0' '\n' | grep ALI
ALIBABA=HOCUSPOCUS

(For more fun with environments, grab environ.c)

Array variables

$ readarray hosts < /etc/hosts
$ for name in "${hosts[@]}"
> do
>   echo $name
> done
127.0.0.1 localhost
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters