SHELLdorado Newsletter 1/2003 - July 6th, 2003

From: Heiner Steven (heiner.steven_at_nexgo.de)
Date: 07/14/03

  • Next message: David Schwartz: "Re: dhcp server spans different subnets?"
    Date: Mon, 14 Jul 2003 22:43:59 +0200
    
    

    SHELLdorado Newsletter 1/2003 - July 6th, 2003

    ================================================================
    The "SHELLdorado Newsletter" covers UNIX shell script related
    topics. To subscribe to this newsletter, leave your e-mail
    address at the SHELLdorado home page:

            http://www.shelldorado.com/

    View previous issues at the following location:

            http://www.shelldorado.com/newsletter/

    "Heiner's SHELLdorado" is a place for UNIX shell script
    programmers providing

         Many shell script examples,
         shell scripting tips & tricks + more...
    ================================================================

    Contents

     o Shell Tip: Returning more than one value from a function (or AWK)
     o Shell Script: "tarmail" - send "tar" archive by e-mail
     o Shell Tip: Print lines of a file in reverse (or random) order
     o Shell Tip: advisory locking for shell scripts

    -----------------------------------------------------------------
    >> Shell Tip: Returning more than one value from a function (or AWK)
    -----------------------------------------------------------------

        A shell function function can return error codes, strings,
        and even multiple values. How? Read on...

        Returning success or failure values from a shell function is
        straightforward, e.g.

            # validinteger - return success if string consists only of
            # numbers
            validinteger () {
                case "$1" in
                    *[!0-9]*) return 1;; # string contains invalid chars.
                    *) return 0;; # only digits from 0-9
                esac
            }

        This function can be used as follows:

            if validinteger "$1"
            then echo "valid number: $1"
            else echo "no valid integer number: $1"
            fi

        Command substitution can be used for a string return value, e.g. the
        function "abspath":

            # abspath - return absolute path name (starting with /)
            abspath () {
                D=`dirname "$1"`
                N=`basename "$1"`
                (cd "$D"; echo "`pwd`/$N")
            }

        The following command will resolve the directory "../bin" to an
        absolute path name (e.g. /home/john/bin), and assign this value to
        the variable "path":

            path=`abspath "../bin"`

        But can a function set more than one variable? It can, using
        a little trick: the function does not directly print the
        results to standard output, but emits variable assignments
        instead. The calling shell has to evaluate them using, no
        surprise, "eval":

            # Read /etc/password, and get home directory and shell name
            set_home_and_shell () {
                awk -F: '
                    $1 == "john" {
                        print "home=" $6
                        print "shell=" $7
                    }
                ' /etc/passwd
            }

        Calling this function could result in an output line like the
        following:

            home=/home/john
            shell=/bin/ksh

        A caller then has to evaluate these assignments, making the
        shell interpret the lines as commands:

            eval "`set_home_and_shell`"
            # $home and $shell are set here

    -----------------------------------------------------------------
    >> Shell Script: "tarmail" - send "tar" archive by e-mail
    -----------------------------------------------------------------

        When sending all the contents of a directory by e-mail,
        nobody has to create "tar" archives manually, tediously
        encode them e.g. using "uuencode", and invoke "mail"
        manually. The following script does all that, resulting in
        commands like

            tarmail john@home.com /home/john

        to send the whole directory hierarchy /home/john to the
        e-mail address john@home.com.

        :
        ############################################################
        # tarmail - create "tar" archive, send it by e-mail

        if [ $# -lt 2 ]
        then
            echo >&2 "usage: tarmail recipient {file|dir} [...]"
            exit 1
        fi

        recipient=$1; shift
        case "$recipient" in
            *@*) ;; # This looks like an e-mail address
            *) echo >&2 "tarmail: probably no valid e-mail address: $recipient"
                exit 1;;
        esac

        for path
        do
            [ -r "$path" ] || continue

            tarfile=$path.tar
            {
                echo "
        This is an uuencoded 'tar' archive. Save it to a file
        (e.g. "mail.uue"), and unpack it using

                    uudecode mail.uue
                    tar xvf $tarfile"
                tar cf - "$path" |
                        uuencode "$tarfile"
            } | mailx -s "$tarfile" "$recipient" || exit 1
        done
        ############################################################

        [ Extended version of this script:
            http://www.shelldorado.com/scripts/cmds/tarmail
        ]

        If your system does not have "mailx", you may need to use
        another e-mail client that's able to set subject lines, e.g.
        "Mail" (with a capital 'M') or just "mail".

        The resulting mails can be read e.g. by MS Outlook, Mozilla,
        and Netscape e-mail clients.

        Well, using uuencode is a spartan way to send mail
        attachments. A more general way is to create MIME file
        attachments, which contain the type of the data that is
        attached (e.g. "image/gif". It can be used by the receiving
        e-mail client to automatically start the right program to
        display it (whatever this may be, for "application/tar"). The
        following article goes into the details, and lists some
        helper programs and scripts that are useful to have:

            http://www.shelldorado.com/articles/mailattachments.html

    -----------------------------------------------------------------
    >> Shell Tip: Print lines of a file in reverse (or random) order
    -----------------------------------------------------------------

        For printing lines in reverse order, i.e. the last line of a
        file first, we use a simple trick: each line gets a line
        number on which we sort, and then remove later on:

            nl -ba < "input" | sort -nr | cut -f2-

        "nl" numbers lines, "-ba" even empty ones. "sort -nr" sorts
        all lines numerically on the first column, descending order.
        "cut" finally removes the first sorting column.

        Now the idea of printing lines in a random order is not too
        far away. It's e.g. useful for processing MP3 play lists, or
        creating random signature files. Instead of printing a
        sequential number, we'll print a random number at the start
        of each line, and sort the lines based on that number:

            awk '{ print rand() " " $0 }' "input" |
                    sort -n | cut -f2-

        Note that this requires a recent version of AWK. Solaris
        users should use "nawk" ("new AWK"), GNU awk (gawk) works
        fine, too.

        A slightly more general version for printing lines in a
        random order is available at the SHELLdorado:

            http://www.shelldorado.com/scripts/cmds/shuffle

    -----------------------------------------------------------------
    >> Shell Tip: advisory locking for shell scripts
    -----------------------------------------------------------------

        Sometimes a script may want to run exclusively. A script
        starting a database server may want to ensure that no other
        instance of the same script is starting the server at the
        same time, or a script creating backups on a tape device
        could ensure that it is only run once at a time.

        This kind of advisory locking for shell scripts can be
        implemented by creating (temporary) directories. Directory
        creation is guaranteed to be atomic, for each process it
        either succeeds or it fails, but it cannot succeed for more
        than one process at the same time. We take advantage of this
        in the following script for advisory locking:

            :
            # makelock - advisory locking for shell scripts

            if [ $# -ne 1 ]
            then
                echo >&2 "usage: makelock lockname"
                exit 1
            fi

            lockname=$1; shift
            lockpath=/tmp/$lockname

            try=1 # first of 5 tries
            until mkdir "$lockpath" >/dev/null 2>&1
            do
                try=`expr $try + 1`
                if [ $try -gt 5 ]
                then
                    echo >&2 "giving up on $lockname"
                    exit 1
                fi
                sleep 5 # give process time to release lock
            done

            # We now have the lock!

        When the program no longer needs the lock, it can use
        "rmdir /tmp/$lockname" to free it. A usage example:

            if makelock Restore
            then
                # Free lock when program terminates (exit or signal)
                trap 'rmdir /tmp/Restore' 0
                trap "exit 2" 1 2 3 15

                echo >&2 "restore: starting to restore data..."
                # do some work...
            else
                echo >&2 "restore: cannot acquire lock: Restore"
                exit 1
            fi

        Note that this kind of locking does not handle "stale" locks,
        i.e. locks that have been acquired, but have not been released
        by a program (e.g. because of a crash, or "kill -9").

        The program "mklock" is an extended version of "makelock",
        which also implements "unlocking":

            http://www.shelldorado.com/scripts/quickies/mklock

    ----------------------------------------------------------------
    If you want to comment on this newsletter, have suggestions for
    new topics to be covered in one of the next issues, or even want
    to submit an article of your own, send an e-mail to

            mailto:heiner.steven@shelldorado.com

    ================================================================
    To unsubscribe, send a mail with the body "unsubscribe" to
    newsletter@shelldorado.com
    ================================================================


  • Next message: David Schwartz: "Re: dhcp server spans different subnets?"

    Relevant Pages

    • Re: detect shell script language
      ... In the 'old' days, when a user typed in a command, the interactive shell would immediately pass it off to 'exec' to execute. ... So, on return from exec with an error status, the shell would fork a copy of itself to try and run the script. ... As a result of the above, it was hard to tell whether the script was a Bourne shell or C shell, so the convention was introduced of using the Bourne shell no op command, as the first line in a Bourne shell script. ...
      (Debian-User)
    • Re: Call for input on comp.unix.shell FAQ
      ... >> questions and just tell people to FAQ it. ... The other level is how to write shell scripts. ... How can I remove whitespace characters within file names? ... Why one shouldn't use "echo" in a script? ...
      (comp.unix.shell)
    • SHELLdorado Newsletter 1/2003 - July 6th, 2003
      ... The "SHELLdorado Newsletter" covers UNIX shell script related ...
      (comp.unix.shell)
    • Re: Affecting Institutional Change (Yeah Right)
      ... provides labs in most non-dorm buildings replete with the wonderful ... be run from a shell, no idea what an executable was, and, in fact, ... IDE program, go through a ton of menus to pick the right script, go ... To UNSUBSCRIBE, email to debian-user-REQUEST@xxxxxxxxxxxxxxxx ...
      (Debian-User)
    • SHELLdorado Newsletter 1/2003 - July 6th, 2003
      ... The "SHELLdorado Newsletter" covers UNIX shell script related ...
      (comp.unix.admin)

  • Quantcast