我希望编写一个 cron 包装器,将所有输出记录在文件夹中$CRON_LOG_DIR
。
其用法如下:
* * * * * $CRON_WRAPPER "<job name>" "command"
stdout
这将记录以下stderr
的完整输出command
:
$CRON_LOG_DIR/<date>/<job_name>/command_timestamp.log
我正在使用下面的脚本$CRON_WRAPPER
,但是,它似乎没有记录命令由多个命令组成的情况,stdout
例如command
* * * * * $CRON_WRAPPER "<job name>" "command1 && command2 && command3"
为什么?
下面是完整的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
如果脚本的第一个参数是jobname
,第二个参数是command1 && command2 && command3
,那么您在变量中构建的命令joined
类似于
command1 && command2 && command3>> /path/to/cron/log/dir/May_12_2015/jobname_2015-05-12_01-09-25.log 2>&1
你调用eval
这个字符串,它就会被正常解析。重定向仅适用于“command3”。
您希望将第二个参数视为 shell 片段,而不是 shell 片段的前缀。所以不要将东西连接到它上面。重定向直接属于脚本,而不是在 下eval
,因为您直接在脚本中指定它,而不是通过需要解析的字符串。请注意,如果jobname
包含任何 shell 特殊字符,您的代码将会中断,例如$CRON_WRAPPER $(touch /tmp/foo) stuff
将执行代码touch /tmp/foo
。
脚本的另一个问题是,如果参数超过两个,则在参数之间添加逗号,这是没有意义的。用空格将它们连接起来会更有意义,这很简单"$*
。 (对于使用逗号作为分隔符进行连接,您所做的过于复杂。在 zsh 中,请使用${(j:,:)@}
。)
# Joining commands:
替换脚本中以by开头的部分
eval "$*" >>$CRON_LOG_FILE 2>&1