CS 279 - Week 8 Lab - 10-10-12

*   both test and [ ] can contain a variety of
    tests (those listed in the link on the
    public course web page, for example)

    ...you can play with test from the command line,
    BUT using it with && (short-circuiting boolean
    and) and an echo can let you see if the test
    succeeded -- only if it succeeded will the
    echo be evaluated:

    test -e pig.txt && echo 'you have that file'
    
    ...you'll only see
    you have that file
    ...IF pig.txt exists;

    -e file 	    - true if file exists

    -f file         - true if regular file

    -d file         - true if file is a directory

    -h file         - true if file is a symbolic link
  
    -r file         - true if file is readable by you

    -w file         - ...is writable by you

    -x file         - ...is executable by you

    -s file         - ...exists and is not empty

*   you can use ! in front of one of these
    to test for its negation --

    test ! -e pig.txt && echo 'file does not exist'

NOTE:
*   you can EXIT a bash shell script with a particular
    exit status by using the exit command followed
    by the desired integer exit status

    if [ ! -e $desired_file ]
    then
        echo "$0: $desired_file does not exist"
        echo "    ...exiting"
        exit 1
    fi

    *   if you are exiting "prematurely", it is good
        style to use a non-zero exit status
        (and that's now a class coding standard, too)

    *   example using exit: exit-ex.sh

*   you can see if a string is empty (length of 0) or not
 
    -z string   - true if the string is empty (length
                 of 0)

    -n string   - true if the string is not empty
                  (nonzero length)

*   some binary/more comparative testers: (still
    in [ ] or with test)

    file1 -nt file2   - true if file1 is newer than
                        file2

    file1 -ot file2   - true if file1 is older than
    	      	        file2

    string1 = string2 - true if string1 is identical
                        to string2

    string != string2 - true if string1 is NOT 
    	      	      	identical to string2

 
    *   BEWARE - be prepared for spaces in filenames!

        advice from:
http://www.davidpashley.com/articles/writing-robust-shell-scripts.html

        if [ $filename = "foo" ]

        ...will FAIL if $filename contains a space

        if [ "$filename" = "foo" ]

        ...WON'T fail if $filename contains a space

*   this is also of concern when you are grabbing
    all of the command-line arguments in a shell
    script:

    for i in $@
    do
        echo $i
    done

    ...say this is in a script for-quotes.sh --
    if you call it with:

    for-quotes.sh moo "arf oink"
    ...you'll get THREE lines of output:
    moo
    arf
    oink

    ...NOT the two you probably expected:
    moo 
    arf oink

    *   the blank in the second command line argument is making it
        look like multiple arguments;

    *   this won't happen if you double-quote the $@:

    for i in "$@"
    do
        echo $i
    done

    ...now, you'll get the desired 1-line of output for each 
       command-line argument, even if one happens to contain blanks

    ...for-quotes.sh now has BOTH of the above loops, so you
       can compare and contrast their behavior

*   there are also tests for comparing integers

    int1 -eq int2    --- true if int1 is identical to
                         int2
    int1 -ne int2    ...not identical
    int1 -lt int2    ...less than
    int1 -gt int2    ...greater than
    int1 -le int2    ...less than or equal
    int1 -ge int2    ...greater than or equal

    *   more-than-5.sh shows an example of using one of the
        above to see if the number of command-line arguments
	(obtainable using $#) is acceptable for that shell script;

*   talking a little more about operators that
    work inside [[ ]]

    string =~ regex   true if string matches
                      regex

    *   remember NOT to put quotes around
        the regex!

*   note that && and || are short-circuited boolean-and and
    boolean-or operators (respectively) inside [[ ]]

*   string = filename-expansion-pattern
    string == filename-expansion-pattern

    (notice, this is different than = in [ ] )

    *   glob-play.sh tries this out;

*   can use ( ) to change evaluation
    precedence in [[ ]], too;

*   OH -- and what if you'd like to loop through all of the
    lines in a particular file?

    ...there's more than one way, BUT this way DOES
       maintain one-line-per-loop-iteration behavior
       (even if a line contains blanks):

    while read line
    do
        echo "\$line: $line"
    done < fodder.txt

    notice the 
    read 
    ...as part of the while condition, and the 
    < filename 
    AFTER the while loop's done !
    done < filename

    *   read-lines-ex.sh shows this in action