Bourne Shell scripts

  Language Dazibao:
    
    - All variables are string variables.
    - Read variable with $ prefix, write without.
    - Use build-in variables $? (exit code), $#, $0..$9 (argc, argv[])
    - Understand strong - '', weak - "" and redirecting - `` quotation.
    - Use expr function for arithmetics and string manipulation.
    - Use test for logical operations and comparison. Result is in $?.

  1. Comments

     #!/bin/bash
     #
     # first row is telling to the system which shell should be
     # implemented with this script

  2. Constant data in code

    Strings           'this is $strong quoting'  # no substitution
                      "this is $weak quoting"    # values substituted
                      `expr 2 + 3`               # 5 result redirected
                     $(expr 2 + 3)               # 5, with XML flavour

  3. Variable data in code

    All primary types of data 
        - boolean,
        - bit set,
        - finite integer, 
        - floating point number

    are stored as formatted strings (in human readable form).
    Variables does not require declaration. 
    Newer versions of bash support one-dimensional arrays. (a[3]=Abcd)
    Structures and Containers are not available.
    
      % VAR = "My variable"  # create / write
      % echo $VAR            # read
      % unset $VAR           # free memory allocated to $VAR

    Special variables

      $?       return code of the last command

      $#       number of command line arguments
      $*       whole string of arguments as one string
      $0       script filename
      $1 .. $n command line arguments

  4. Expressions

    Expressions are evaluated using expr utility
    Numeric expressions with integers: (+ - * / %)

      +    plus
      -    minus
      *    multiplication
      /    division
      %    modulo (returns the remainder of an integer division)

      % expr 18 + 4

    String manipulations: (index match length substr)

      # index: position in string of first character in substring 
               that matches. 
      # substr: print substring, starting position & length specified      
      # length: length of string                                           
      # 'match' operations similarly to 'grep'                             

      a=1234zipper43231                                                    

      # index: position in string of first character in substring 
               that matches.                                       
      b=`expr index $a 23`                                                 
      echo Numerical position of first 2 in $a is $b.                     
                                                                             
      # substr: print substring, starting position & length specified      
      b=`expr substr $a 2 6`                                               
      echo Substring of $a, starting at 2 and 6 chars long is $b.
                                                                             
      # length: length of string                                           
      b=`expr length $a`                                                   
      echo Length of $a is $b.                                             
                                                                             
      # 'match' operations similarly to 'grep'                             
      b=`expr match $a [0-9]*`                                             
      echo Number of digits at the beginning of $a is $b.                  
      b=`expr match $a '\([0-9]*\)'`                                       
      echo The digits at the beginning of $a are $b.                       

    Strings concatination:
          
      % a="Uno"; b="Duo"; c=$a$b; echo $c       # UnoDuo
      % d="Just${c}Between"; echo $d            # JustUnoDuoBetween

  5. Flow control
  
    Test tool
    ---------

    Use "test" named tool to evaluate expression to boolean.
    Result is returned in exit code: 0 - true, 1 - false and 
    is stored in $? special variable.

    Logical operations with exit codes

      !      logical NOT
      &&     logical AND
      ||     logical OR

      cp file1 $var || exit 1

      if [ -e file1 ] && [ -e file2 ]
      then
          echo "both files exists"
      fi

    String comparison

      -z     string is "null", that is, has zero length
      -n     string is not "null".
      =      is equal to ($a = $b)
      !=     is not equal to ($a != $b)
      \<     is less than, in ASCII alphabetical order ($a \< $b)
             Note that the "<" needs to be escaped.
      \>     is greater than, in ASCII alphabetical order ($a \> $b)
             Note that the ">" needs to be escaped.

    Filesystem

      -e    file exists

      -f    file is a regular file
      -s    file is not zero size
      -d    file is a directory
      -b    file is a block device (floppy, cdrom, etc.)
      -c    file is a character device (keyboard, sound card, etc.)
      -p    file is a pipe
      -L    file is a symbolic link
      -S    file is a socket
         
      -r    file is readable (has read permission)
      -w    file has write permission
      -x    file has execute permission
         
      -g    group-id flag set on file
      -u    user-id flag set on file
      -k    "sticky bit" set (if user does not own a directory that has
            the sticky bit set, she cannot delete files in it, not even 
            files she owns)
         
      -O    you are owner of file
      -G    group-id of file same as yours
         
      -t n  file descriptor n is open. This usually refers to stdin, 
            stdout, and stderr (file descriptors 0 - 2).
         
      f1 -nt f2    file f1 is newer than f2
      f1 -ot f2    file f1 is older than f2

      f1 -ef f2    files f1 and f2 are links to the same file
         
    Integer comparison

      -eq    is equal to ($a -eq $b)
      -ne    is not equal to ($a -ne $b)
      -gt    is greater than ($a -gt $b)
      -ge    is greater than or equal to ($a -ge $b)
      -lt    is less than ($a -lt $b)
      -le    is less than or equal to ($a -le $b)

    Logical expressions

      (expression)   override normal precedence of the operators
      ! expression   logical not
      -a             logical and
      -o             logical or

  Operators
  ---------

    exit N   - exit script with exit code N

    if test expression
    then
      ...
    fi

    while test expression        until test experssion
    do                           do
      ...                          ...
    done                         done

    break    - use this operator to exit do - done loop
    continue - use this operator to resume next iteration

    for vVar in 1 2 4 8          
    do                           
      echo $vVar                 
    done

    Note 1: Use 
                for vVar in *; do ... ;done

            to iterate in directory of files

    Note 2: Use seq tool to generate lists
            seq 5     # (stop)             1 2 3 4 5
            seq 3 5   # (start stop)       3 4 5
            seq 3 2 7 # (start step stop)  3 5 7

            Several operators on the same row should be separated by ;

            for vVar in Alpha Beta Gamma; do
              echo $vVar
            done

    case $vVar in
      "$condition1" )
        command...
      ;;
   
      "$condition2" )
        command...
      ;;
    esac

    Example

      #!/bin/bash                                                             
      case $1
        [a-z]   ) echo "Lowercase letter";;                            
        [A-Z]   ) echo "Uppercase letter";;                            
        [0-9]   ) echo "Digit";;                                       
        *       ) echo "Punctuation, whitespace, or other";;           
      esac                                                             
      # Allows ranges of characters in [square brackets].              

  6. Visibility and encapsulation

     - Write each function in separate file.

     - If only script ascript uses function foo, ascript_foo name
       is recommended for this function. Otherwise anamespace_foo
       name is good for functions used in more than one script.
      
     - Also ugly and useless function implementation was introduced
       in late versions of Bourne Shell (after 1979).

         foo () {                                                                   
           # Checks if any params.                                                   
           if [ -z $1 ]                                                              
           then                                                                      
             echo "No parameters passed to function."                                
             return 0                                                                
           else                                                                      
             echo "Param #1 is $1."                                                  
             return 1
           fi                                                                        
         }

         foo
         foo abc                                                                           

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  How to insert data

    - from command prompt

      % read a # now write the value for just created a variable
      % echo $a
      % echo # wait for key is pressed

    - inside script source

      cat > /etc/resolv.conf <".
    $PS3        The tertiary prompt, displayed in a select loop.
    $PS4        The quartenary prompt, shown at the beginning of each 
                line of output when invoking a script with the -x 
                option. It displays as "+".
    $PWD        working directory (directory you are in at the time)
    $OLDPWD     old working directory (previous directory you were in)
    $DIRSTACK   contents of the directory stack (affected by pushd and
                popd)
    $PPID       the process id (pid) of the currently running process
                This corresponds to the pidof command
    $MACHTYPE   machine type
    $HOSTTYPE   host type
    $OSTYPE     operating system type
    $EDITOR     the default editor invoked by a script, 
                usually vi or emacs.
    $IGNOREEOF  ignore EOF: how many end-of-files (control-D) the shell
                will ignore before logging out.
    $TMOUT      If the $TMOUT environmental variable is set to a 
                non-zero value time, then the shell prompt will time 
                out after time seconds. This will cause a logout.
    $SECONDS    The number of seconds the script has been running.
    $REPLY      The default value when a variable is not supplied to 
                read. Also applicable to select menus, but only 
                supplies the item number of the variable chosen, not 
                the value of the variable itself.
    $SHELLOPTS  the list of enabled shell options, a readonly variable
    $BASH       the path to the bash binary itself, usually /bin/bash
    $BASH_ENV   an environmental variable pointing to a bash startup 
                file to be read when a script is invoked

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  Binary tools recommended for portable Unix scripts:

    echo        TRUE         cp          touch
    cat         FALSE        mv          tar  
    tr                       ln          cmp  
    sed         expr         rm          diff 
    awk         test         mkdir       egrep
                seq          rmdir       grep 
                             ls          sort 
                             pwd         sleep