Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 19 Jul 2008 20:23:01 -0400 (EDT)
From:      vogelke+software@pobox.com (Karl Vogel)
To:        freebsd-questions@freebsd.org
Subject:   Re: how to simulate a user's crontab?
Message-ID:  <20080720002301.A32C9B7B6@kev.msw.wpafb.af.mil>
In-Reply-To: <487F1097.31417.718F23E@iwrtech.iwr.ru.ac.za>

next in thread | previous in thread | raw e-mail | index | archive | help
>> On Thu, 17 Jul 2008 09:27:51 +0200, 
>> "DA Forsyth" <iwrtech@iwr.ru.ac.za> said:

D> John, it is not a permissions issue, but rather a path issue.  Do as the
D> other poster suggested and run a cron job to dump the environment and you
D> will see that the PATH inside a cron job is very rudimentary.  Either add
D> what you need to it in the crontab or cron job, or always use absolute
D> paths for everything in a cron entry.

D> alternatively, set up an AT job as the user, then find the script generated
D> by at and grab a copy (/var/spool/cron ???).  You can use that copy as the
D> basis for all cron scripts for that user, and always have the 'user'
D> environment set up correctly.

   I use templates for most of the things I write, so I don't end up making
   the same stupid off-by-one mistakes for things like handling command-line
   arguments.  My template for a production shell script is below.

   * Why use the Korn shell instead of bash?  "size" prints out the size of
     the text, data, and uninitialized data segments and their total for
     a given program.  On Solaris:

       me% size /bin/ksh /bin/bash
       /bin/ksh:  166555 +  2022 +  6438 = 175015
       /bin/bash: 535476 + 74216 + 13712 = 623404

     BSD numbers have the same general idea.  Bash is >3 times heavier than
     KSH in terms of memory use; if you need all that, fine, but if not,
     consider something lighter.  David Korn is one of the brightest minds
     at AT&T, and any shell he writes to correct deficiencies in the original
     Bourne shell deserves a serious look.

   * Always set your PATH and umask to something safe.  This way, you avoid
     unpleasant surprises if someone else runs your script, or if it's run
     from cron.

   * It should be easy to do things you do frequently.  I use short functions
     like "logmsg" to write to the system log for long-running scripts,
     and "die" to print a useful error message and exit.  This way, sanity
     checking becomes much less tedious, and if you want to change the format
     or destination of log messages, the change is made in *one* place.

   * Using a template makes it easier to be consistent when choosing things
     like command-line options; in just about everything I write, "-d"
     turns on debugging output, "-h" prints help, etc.

     This might not be a big deal if you're the only user, but if you work
     a help desk and you need to know why a script barfed all over itself
     when a customer's on the phone, it's a blessing.

   * It should be easy to find out what version is being run and where the
     source code is.  The "-v" option prints the version and date, and the
     "-w" option prints the source location from the revision system I use:

       me% ./doit -v
       doit  v1.1  2008/02/24 13:02:35

       me% ./doit -w
       /src/script/RCS/doit,v

-- 
Karl Vogel                      I don't speak for the USAF or my company
I remember when sex was safe and flying was dangerous.

---------------------------------------------------------------------------
#!/bin/ksh
#
# NAME:
#    doit
#
# SYNOPSIS:
#    doit [-dhuvw] [-o outfile] [infile ...]
#
# DESCRIPTION:
#    program to ...
#
# OPTIONS:
#    "-d" turns debug output on.
#    "-h" prints help and exits.
#    "-o outfile" specifies the optional output file.
#    "-u" prints the UUID and exits.
#    "-v" prints the version and exits.
#    "-w" prints the location of the source code and exits.
#
# AUTHOR:
#    Your name <user [at] whatever [dot] com>
#    Your organization

PATH=/usr/local/bin:/bin:/usr/bin:/usr/sbin
export PATH
umask 022
tag=`basename $0`

# ======================== FUNCTIONS =============================
# logmsg: prints a string to the system log.

logmsg () {
    logger -t $tag "$*"
}

# die: prints an optional argument to stderr and exits.
# This works in subshells and loops, but may not exit with
# a code other than 0.

die () {
    echo "$tag: ERROR -- $*" >& 2
    exit 1
}

# usage: prints an optional string plus part of the comment
# header (if any) to stderr, and exits with code 1.

usage () {
    lines=`egrep -n '^# (NAME|AUTHOR)' $0 | cut -f1 -d:`

    (
        case "$#" in
            0)  ;;
            *)  echo "usage error: $*"; echo ;;
        esac

        case "$lines" in
            "") ;;

            *)  set `echo $lines | sed -e 's/ /,/'`
                sed -n ${1}p $0 | sed -e 's/^#//g' |
                    egrep -v AUTHOR:
                ;;
        esac
    ) >& 2

    exit 1
}

# Print the UUID for this script.  Should be based on
# something unique, like date-time-hostname.

myuuid () {
    lsedscr='s/UUID: //
    s/\$//g'
    lid='$UUID: ee96ec96-5bab-3443-b0d4-e0d2c96a4ffd $'
    echo "$lid" | sed -e "$lsedscr"
}

# Print the current version and source location.

version () {
    lsedscr='s/RCSfile: //
    s/.Date: //
    s/,v . .Revision: /  v/
    s/\$//g'

    lrevno='$RCSfile: doit,v $ $Revision: 1.1 $'
    lrevdate='$Date: 2008/02/24 13:02:35 $'
    echo "$lrevno $lrevdate" | sed -e "$lsedscr"
}

where () {
    lsedscr='s/Source: //
    s/\$//g'
    lsrc='$Source: /src/script/RCS/doit,v $'
    echo "$lsrc" | sed -e "$lsedscr"
}


# ======================== MAIN PROGRAM ==========================
# Handle command line arguments.

outfile=
while getopts dho:uvw c
do
    case $c in
        d)  debug=yes ;;
        h)  usage ;;
        o)  outfile="$OPTARG" ;;
        u)  myuuid; exit 0 ;;
        v)  version; exit 0 ;;
        w)  where; exit 0 ;;
        \?) usage "invalid argument" ;;
    esac
done
shift `expr $OPTIND - 1`

# Real work starts here.

for arg in $*
do
    echo "arg: [$arg]"
done

# Example: using "die" for one-line sanity checks.

test -d "$outfile" && die "cannot write to a directory"

# Example: logmsg creates a syslog entry like this:
#      Jul 19 19:07:27 hostname doit: output file: [/tmp/x]

test "$debug" = "yes" && logmsg "output file: [$outfile]"

# Example: create a *safe* temporary file:
#    -rw------- 1 vogelke vogelke 0 Jul 19 19:27 /tmp/doit.3aaaRt

tmpfile=`mktemp -q /tmp/$tag.XXXXXX`
case "$?" in
    0) trap "rm -f $tmpfile; exit 1" ERR ;; # ksh only
    *) die "$tag: can't create tmpfile" ;;
esac

rm -f $tmpfile
exit 0



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20080720002301.A32C9B7B6>