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>

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!'

'[' 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.'

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

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

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
  • 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

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

Exercises

edit
  • write a script that takes as arguments a file and a folder, and tries to copy the file into the specified folder:
    1. write the script without any checks;
    2. make it check if the source exists, and if not refuse to do anything (exit);
    3. make it check if the destination exists, and if so refuse to do anything (exit);
    4. make it check if the destination folder exists, and if not tries to create it;
    5. 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 ...;)