Operating systems 1 -- 2008-2009 -- info.uvt.ro/Laboratory 4
Quick links: front; laboratories agenda, 1, 2, 3, 4, 5, 6, projects, evaluation, tools, references.
Exit status
edit- each process has an exit status;
- if a command succeeds its exit status is 0:
true echo "${?}" cat /etc/passwd echo "${?}"
- if a command fails its exit status is different that 0:
false echo "${?}" cat /tmp/non-existing-file echo "${?}"
- to exit from a script with a certain status:
exit <status>
- references:
Command chaining
edit- syntax:
<command> [argument] ... { && <command> [argument] ... } ... <command> [argument] ... { || <command> [argument] ... } ...
- execute something if a command has succeeded:
true && echo 'command succeeded.' false && echo 'command succeeded.' test -f /etc/passwd && echo 'file exists.'
- execute something if a command has failed:
true || echo 'command failed!' false || echo 'command failed!' test -f /tmp/non-existing-file || echo 'file does not exist!'
- references:
'[' or test command
edit- syntax: please consult the man page;
- testing if an argument is empty:
test -z "${1}" || echo 'empty.' test ! -z "${2}" && echo 'non-empty.' test -n "${1}" || echo 'empty.' test -n "${1}" && echo 'non-empty.'
- testing if a file exists (otherwise creating it):
test -f /tmp/some-file-1 || nano /tmp/some-file-1 test ! -f /tmp/some-file-2 && nano /tmp/some-file-2
- testing if a directory exists (otherwise creating it):
test -d /tmp/some-directory || mkdir /tmp/some-directory
- testing if two arguments are equal:
test "${1}" == "${2}" || echo 'non equal.' test "${1}" != "${2}" && echo 'non equal.'
- testing if two arguments are less one than another (integer comparison):
test "${1}" -lt "${2}" && echo 'lesser.' test "${2}" -lt "${2}" || echo 'greater.'
- important operators:
- !;
- string: -z, -n, =, !=;
- numbers: -eq, -ne, -gt, -lt, -le, -ge;
- files: -e, -f, -d, -x, -w;
- references:
Command grouping and sub-shells
edit- block syntax:
{ <command> [arguments] ... ; <command> [arguments] ... ; ... ; } { <command> [arguments] ... <command> [arguments] ... ... }
- simple example:
{ echo a ; echo b ; }
- do not forget the last ;:
{ echo a ; echo b }
- if we want to take more actions if a file does not exist:
cat /tmp/expected-file-1 || { echo 'file does not exist; creating...' ; sleep 5 ; nano /tmp/expected-file-1 ; }
- or:
cat /tmp/expected-file-2 || { echo 'file does not exist; creating...' sleep 5 nano /tmp/expected-file-2 }
- sub-shell syntax: just like the block syntax, but with () instead of {};
- if we issue exit from a sub-shell only it terminates, not the entire shell:
( exit 1 ; ) || echo 'sub-shell failed!'
- in contrast if we issue exit' from a block, the current shell exits:
{ exit 1 ; } || echo 'block failed!'
Loops and branches
editif
edit- syntax:
if <command> <argument> ... ; then { <command> <argument> ... ; } ... else { <command> <argument> ... ; } fi if <command> <argument> ... then <command> <argument> ... ... else <command> <argument> ... ... fi
- testing if a file exists, and if not creating an empty one:
if test ! -f /tmp/expected-file-3 ; then touch /tmp/expected-file-3 ; fi
- testing if a file exists, and if not editing it:
if test ! -f /tmp/expected-file-4 then echo 'file does not exit; creating...' touch /tmp/expected-file-4 sleep 1 nano /tmp/expected-file-4 else echo 'file exists.' fi
- references:
case
edit- syntax:
case <string> in ( <pattern> { | <pattern> } ... ) <command> <argument> ... ... ;; ... esac
- example script for controling a daemon:
case "${1}" in ( start ) echo 'starting daemon...' daemon & ;; ( stop ) echo 'stopping daemon...' killall daemon ;; ( * ) echo "unknown action ${1}!" ;; esac
- references:
for
edit- syntax:
for <variable> in <string> ... ; do { <command> <argument> ... ; } ... done for <variable> in <string> ... do <command> <argument> ... ... done
- simple for command:
for a in 1 2 3 4 ; do echo "${a}" ; done
- or:
for a in 1 2 3 4 do echo "${a}" done
- editing all .bash<something> files in the current folder:
for file in ./.bash* ; do nano "${file}" ; done
- or:
for file in ./.bash* do echo "editing file ${file}..." sleep 5 nano "${file}" done
- references:
while
edit- syntax -- using a test command:
while <command> <argument> ... ; do { <command> <argument> ... ; } ... done while <command> <argument> ... do <command> <argument> ... ... done
- syntax -- reading lines:
while read variable ; do { <command> <argument> ... ; } ... done while read variable do <command> <argument> ... ... done
- waiting for a file to be created:
while test ! -f /tmp/expected-file-5 ; do sleep 1 ; done
- or:
while test ! -f /tmp/expected-file-5 do echo 'file does not exit; waiting to be created...' sleep 1 done
- doing something with all files (recursively in a folder):
find /etc -type f | while read file do echo "found file ${file}." done
- references:
Exercises
edit- write a script that takes as arguments a file and a folder, and tries to copy the file into the specified folder:
- write the script without any checks;
- make it check if the source exists, and if not refuse to do anything (exit);
- make it check if the destination exists, and if so refuse to do anything (exit);
- make it check if the destination folder exists, and if not tries to create it;
- make it check if the source is a folder (and if so copy it recursively);
- write a script that takes as argument a file name, and writes to the standard output if it represent a file, folder, something else, or if it doesn't exist;
- write a script like the previous one, but which takes any number of arguments that represent file names; (hint: use for;)
- write a script that finds all the users defined in the /etc/passwd file (passwd.5); (hint: use twice grep with -o, or sed;)
- write a script that uses the previous one, and checks for which users there is a homedir (/home/<username>); (hint: use ./find-users.sh | while read user ...;)