0

I am hoping to write a cron wrapper that records all output in a folder $CRON_LOG_DIR.

It would be used as, e.g., follows:

* * * * * $CRON_WRAPPER "<job name>" "command"

which would record the full output from stdout and stderr of command under:

$CRON_LOG_DIR/<date>/<job_name>/command_timestamp.log

I am using the script below for $CRON_WRAPPER, however, it does not seem to record stdout for command when command is made of multiple commands, e.g.

* * * * * $CRON_WRAPPER "<job name>" "command1 && command2 && command3"

Why?

Below is the full CRON_WRAPPER

#!/usr/bin/env zsh
COMMAND_NAME=$1
shift

DATE=$(date +%B_%d_%Y)
TIMESTAMP=$(date +%Y-%m-%d_%H-%M-%S)

THIS_CRON_LOG_DIR=$CRON_LOG_DIR/$DATE
mkdir -p $THIS_CRON_LOG_DIR

CRON_LOG_FILE=${THIS_CRON_LOG_DIR}/${COMMAND_NAME}_${TIMESTAMP}.log

# Joining commands:
to_join=$@
joined=$(printf ",%s" "${to_join[@]}")

# Redirecting all output to our logging file:
joined=${joined:1}">> $CRON_LOG_FILE  2>&1"

# Finally evaluating the command
eval $joined
1

If the first argument to the script is jobname and the second is command1 && command2 && command3 then the command you build up in the joined variable is something like

command1 && command2 && command3>> /path/to/cron/log/dir/May_12_2015/jobname_2015-05-12_01-09-25.log  2>&1

You call eval on this string, and it's parsed normally. The redirection only applies to `command3.

You want to treat the second argument as a shell snippet, not as a prefix of a shell snippet. So don't concatenate stuff to it. The redirection belongs directly in the script, not under eval, since you're specifying it directly in the script and not via a string that needs to be parsed. Note that your code would break if jobname contained any shell special character, e.g. $CRON_WRAPPER $(touch /tmp/foo) stuff would execute the code touch /tmp/foo.

Another problem with your script is that you're putting commas between the arguments if there are more than two, which doesn't make sense. Joining them with spaces would make more sense, and that's simply "$*. (For joining with commas as separators, what you did is overly complex. In zsh, use ${(j:,:)@}.)

Replace the part of the script starting with # Joining commands: by

eval "$*" >>$CRON_LOG_FILE  2>&1
  • Thanks! I can't believe I didn't think I was concatenating with a comma! – Amelio Vazquez-Reina May 12 '15 at 1:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.