我有一个bash脚本,用于检查由cron作业创建的一些日志文件,这些日志文件在文件名中有时间戳(直到第二个)。它使用以下代码:
CRON_LOG=$(ls -1 $LOGS_DIR/fetch_cron_{true,false}_$CRON_DATE*.log 2> /dev/null | sed 's/^[^0-9][^0-9]*\([0-9][0-9]*\).*/\1 &/' | sort -n | cut -d ' ' -f2- | tail -1 )
if [ -f "$CRON_LOG" ]; then
printf "Checking $CRON_LOG for errors\n"
else
printf "\n${txtred}Error: cron log for $CRON_NOW does not exist.${txtrst}\n"
printf "Either the specified date is too old for the log to still be around or there is a problem.\n"
exit 1
fi
CRIT_ERRS=$(cat $CRON_LOG | grep "ERROR" | grep -v "Duplicate tracking code")
if [ -z "$CRIT_ERRS" ]; then
printf "%74s[${txtgrn}PASS${txtrst}]\n"
else
printf "%74s[${txtred}FAIL${txtrst}]\n"
printf "Critical errors detected! Outputting to console...\n"
echo $CRIT_ERRS
fi
所以这段代码工作正常,但我现在正在尝试清理我的脚本并在所有脚本的顶部实现set -e。当我对此脚本执行此操作时,它将以错误代码1退出。请注意,我在第一个语句转储到/ dev / null时出错。这是因为有些日子里文件中包含“true”字样,其他日期则为“false”。无论如何,我不认为这是我的问题,因为脚本输出“检查xxxxx.log是否有错误”。在退出之前,我将set -e添加到顶部。
注意:$ CRON_DATE变量是从用户输入派生的。我可以从命令行“$。/ checkcron.sh 01/06/2010”运行完全相同的语句,并且它在脚本顶部没有set -e语句的情况下工作正常。
更新:我在我的脚本中添加了“set -x”并缩小了问题范围。输出的最后一位是:
Checking /map/etl/tektronix/logs/fetch_cron_false_010710054501.log for errors
++ cat /map/etl/tektronix/logs/fetch_cron_false_010710054501.log
++ grep ERROR
++ grep -v 'Duplicate tracking code'
+ CRIT_ERRS=
[1]+ Exit 1 ./checkLoad.sh...
所以看起来问题出现在这一行:
CRIT_ERRS=$(cat $CRON_LOG | grep "ERROR" | grep -v "Duplicate tracking code")
感谢任何帮助。 :)
谢谢, 莱恩
答案 0 :(得分:3)
添加set -x
会打印脚本执行的痕迹,可以帮助您诊断错误的来源。
修改:
你的grep返回1的退出代码,因为它没有找到“ERROR”字符串。
编辑2:
我对结肠道歉。我没有测试它。
但是,以下工作(我在喷出之前测试了这个)并避免调用外部cat
。因为您使用子shell的结果设置变量,并且set -e
查看子shell作为一个整体,您可以这样做:
CRIT_ERRS=$(cat $CRON_LOG | grep "ERROR" | grep -v "Duplicate tracking code"; true)
答案 1 :(得分:2)
一旦简单命令以非零退出状态退出,请求set -e
使脚本退出。这与您的ls
命令有害地结合在一起,当被要求列出不存在的文件时,该命令以非零状态退出,这总是适用于您,因为true
和false
变体不共存。
答案 2 :(得分:2)
bash -c 'f=`false`; echo $?'
1
bash -c 'f=`true`; echo $?'
0
bash -e -c 'f=`false`; echo $?'
bash -e -c 'f=`true`; echo $?'
0
请注意,反引号(和$()
)“返回”它们运行的最后一个命令的错误代码。解决方案:
CRIT_ERRS=$(cat $CRON_LOG | grep "ERROR" | grep -v "Duplicate tracking code" | cat)
答案 3 :(得分:1)
将错误消息重定向到/dev/null
不会对脚本返回的退出状态执行任何操作。您的ls
命令未导致错误的原因是因为它是管道的一部分,管道的退出状态是其中 last 命令的返回值(除非{已启用{1}}。
鉴于您的更新,看起来失败的命令是管道中的最后一个pipefail
。 grep
只有在找到匹配项时才会返回grep
;否则返回0
,如果遇到错误,则返回1
。这是2
的危险;即使你不指望它们,事情也会失败,因为set -e
之类的命令即使没有错误也会返回非零状态。它也无法在管道中较早的错误处退出,因此可能会遗漏一些错误。
由geocar或ephemient提供的解决方案(通过grep
管道或使用cat
来确保管道中的最后一个命令成功返回)应该可以帮助您解决这个问题,如果您真的想要使用|| :
。