Chapter 11 Shell Script Basics

Shell Script Basics

(11.1)

The shebang (#!) starts a script followed by the type of shell the script should execute. A bash scripts starts as follows: #!/bin/sh.

Quoting and Literals

(11.2)

Quotes are important. echo $100 or echo "$100" or echo '$100' each mean different things and might give different output (output is: 00, 00, $100 respectively).

When writing scripts and working on the command line, remember what happens whenever the shell runs a command:

  • Before running, the shell looks for variables, globs and other substitutions.
  • Shell passes the results of the substitutions to the command.

grep r.*t /etc/passwd might turn into grep r.input r.output /etc/passwd if you have these files in your active directory. Be careful!

Single quotes wil resolve the example above. As far as the shell is concerned all characters between two single quotes, including spaces, make up a single parameter.

Note: That's why grep 'r.*t' /etc/passwd will work and 'r.*t /etc/passwd'` wont.

Double quotes work just like single quotes, except that the shell expands any variables that appear withing double quotes.

Note: a b c are three parameters while a "b c" are only two.

Special Variables

(11.3)

$1, $2 and all variables named as positive nonzer integers contain the values of the script parameters. The built-in shell command shift can be used to remove the first argument ($1) and advance the rest forward ($2 becomes $1).

Others:

  • $# is the number of arguments
  • $@ reprensents all of a script's arguments
  • $0 holds the name of the script
  • $$ holds the process ID of the shell
  • $? holds the exit code

Exit Codes

(11.4)

When a Unix program finishes it leaves an exit code. When it is 0 it usually means that the program ran without a problem.

Note: If you intend to use the exit code of a command, you must use or store it immediately after running the command.

Note²: When writing shell code that aborts a script, use something like exit 1 or something different from 0.

Note³: Some programs return non-zero exit codes as a result of an operation without trying to tell you they failed. Examples are grep and diff (they return 0 if they match a pattern and 1 if they don't, 2 is then the real error code).

Conditionals

(11.5)

#!/bin/sh
if [[ "$1" = hi ]]; then
    echo 'The first argument was "hi"'
else 
    echo -n 'The first argument was not "hi" -- '
    echo It was '"'$1'"'
fi

Note: [ is actually a program called test.

Note²: Use "$1" when checking parameter lists to not get an error when they are empty.

&& and || are logical constructs (and and or) and can be replaced with -a and -o.

[ -f file ] checks whether file is a regular file (not a directory or special file). A test can be inverted with the ! operator.

File Tests

Mostly unary operations (they require only one argument).

  • -e true if file exists
  • -s true if file is not empty
Operator Tests For
-f regular file
-d directory
-h symbolic link
-b block device
-c character device
-p namped pipe
-S socket
Operator Operator
-r readable
-w writable
-x executable
-u setuid
-g setgid
-k sticky bit

Finally there is the possibility for binary operators. -nt (newer than), -ot (older than) and -ef (compares two files and returns true if they share inode numbers and devices = hard links).

String Tests

Operator Operator
= true if operands are equal
!= true if operands are not equal
-z true if argument is empty
-n true if argument is not empty

Arithmetic Tests

Note: When using numbers use -eq instead of =

Operator Returns true when first argument is .. the second
-eq equal to
-ne not equal to
-lt less than
-gt greater than
-le less than or equal to
-ge greater than or equal to

Matching strings with case example:


#!/bin/sh

case $1 in
    bye)
        echo Fine, bye.
        ;;
    hi|hello)
        echo Nice to see you.
        ;;
    what*)
        echo Whatever.
        ;;
    *)
        echo 'Huh?'
        ;;
esac

Loops

(11.6)

For loops (foreach)


#!/bin/sh
for str in one two three four; do
    echo $str
done

While loops


#!/bin/sh

FILE=/tmp/whiletest.$$;
echo firstline > $FILE
while tail -10 $FILE | grep -q firstline; do
..
done

Command Substitution

(11.7)

The Bourne shell can redirect a command's standard output back to the shell's own command line. You can store the command output in a shell variable by enclosing a command in $().

Note: Consider using a pipeline to xargs (or use the -exec option) if you want to invoke a command on several filenames that you get as a result of a find command.

Note²: The traditional syntax for command substitution is are back-ticks. Use the newer $() instead.

Temporary File Management

(11.8)

The mktemp command can be used to create temporary filenames.


#!/bin/sh

TMPFILE1=$(mktemp /tmp/im1.XXXXXX)
TMPFILE2=$(mktemp /tmp/im2.XXXXXX)

..

rm -f $TMPFILE1 $TMPFILE2

Note: If the script is aborted, the temporary files could be left behind. Use the trap command to create a signal handler to catch the signal that CTRL-C generates and remove the temporary files!

trap "rm -f $TMPFILE1 $TMPFILE2; exit1" INT

Here Documents

(11.9)

Used for a large section of txt.


#!/bin/sh

DATE=$(date)
cat <<EOF
Date: $DATE

The output above is from the Unix date command.
It's not a very interesting command.
EOF

The <<EOF and EOF control the here document.

Extra (slides + notities)

  • Use ( ) for subshell.
  • read var reads from standard input and stores in $var.

(Slides)

Bash command sequence

TODO detail of sequence.

var=$(printf) wordt beter vervangen door printf -v var.

Process substitution kan via <(...) of >(..).

I/O gebeurt via file descriptor, gekoppeld aan tijdelijke named pipe ls -l <(:) >(:). Dit kan een alternatief bieden voor pipes en subshells.

TODO vb van process substitution.

Parameter expansion ondersteunt extended globbing.

TODO vb van parameter expansion.

Arithmetic substitution.

TODO vb van arithmetic substitution.

Speciale variabelen zijn:

  • $0
  • $?
  • $$
  • $-
  • $IFS
  • $REPLY
  • $BASHOPTS & $SHELLOPTS
  • $LINENO
  • $RANDOM
  • $SECONDS
  • $PWD & $OLDPWD
  • $UID
  • ${GROUPS[@]}
  • ${BASH_REMATCH[@]}
  • ${PIPESTATUS[@]}

results matching ""

    No results matching ""