Unix Cron作业stderr到电子邮件和日志文件?

Unix Cron作业stderr到电子邮件和日志文件?,unix,cron,redirect,Unix,Cron,Redirect,我有一份cron工作: $SP_s/StartDailyS1.sh >$LP_s/MirrorLogS1.txt 其中,SP_s是脚本的路径,LP_s是日志文件的路径。这会将stdout发送到日志文件,将stderr发送到我的电子邮件 我该怎么办?: 1) 将stdout和stderr都发送到日志文件, 2) 并将stderr发送到电子邮件 或者换一种说法:stderr同时指向日志文件和电子邮件,stdout仅指向日志文件 更新: 到目前为止,我得到的答案中没有一个符合我制定的标准,或者

我有一份cron工作:

$SP_s/StartDailyS1.sh >$LP_s/MirrorLogS1.txt
其中,
SP_s
是脚本的路径,
LP_s
是日志文件的路径。这会将stdout发送到日志文件,将stderr发送到我的电子邮件

我该怎么办?:
1) 将stdout和stderr都发送到日志文件,
2) 并将stderr发送到电子邮件

或者换一种说法:stderr同时指向日志文件和电子邮件,stdout仅指向日志文件

更新: 到目前为止,我得到的答案中没有一个符合我制定的标准,或者似乎不适合CRON的工作

我看到了这个,它的目的是“将STDOUT和STDERR从一个命令发送到一个文件,然后将STDERR发送到另一个文件”(由zazzybob在unix.com上发布),这似乎接近于我想要做的事情,我想知道它是否会激励比我更聪明的人:

(( my_command 3>&1 1>&2 2>&3 ) | tee error_only.log ) > all.log 2>&1 

我希望cron将STDERR发送到电子邮件,而不是“另一个文件”。

我假设您使用的是bash,您可以像这样重定向stdout和STDERR

1> LOG_FILE
2> LOG_FILE
发送一封邮件,邮件正文中包含stderr,如下所示

2> MESSAGE_FILE
/bin/mail -s "SUBJECT" "EMAIL_ADDRESS" < MESSAGE_FILE
2>消息文件
/bin/mail-s“主题”“电子邮件地址”
我不确定你是否能像这样只用一段话就完成上面的内容

/bin/mail -s "SUBJECT" "EMAIL_ADDRESS" <2

/bin/mail-s“SUBJECT”“EMAIL_ADDRESS”如果您可以将stdout/err放在单独的文件中,那么应该这样做:

($SP_s/StartDailyS1.sh 2>&1 >$LP_s/MirrorLogS1.txt.stdout) | tee $LP_s/MirrorLogS1.txt.stderr
如果您想将stdout和stderr合并到一个文件中,而stderr还没有进入到它自己的流中,那么这有点棘手

应该这样做(省略错误检查、清理和通用健壮性):

#/垃圾箱/垃圾箱
CMD=../StartDailyS1.sh
日志文件=…../MirrorLogS1.txt
先进先出=/tmp/FIFO
>$LOGFILE
mkfifo$FIFO 2>/dev/null | |:
tee<$FIFO-一个$LOGFILE>&2&
$CMD 2>$FIFO>>$LOGFILE

stderr被发送到一个命名管道,由
tee(1)
拾取,它被附加到日志文件中(其中还附加了您的命令的stdout),并返回到常规stderr。

因为我只是在查看tee的信息页面(试图找出如何做同样的事情),我可以为您回答最后一点

这是实现这一目标的主要途径:

(( my_command 3>&1 1>&2 2>&3 ) | tee error_only.log ) > all.log 2>&1
但将“error\u only.log”替换为“>(email\u命令)”


注意:根据tee的文档,这将在bash中工作,但在/bin/sh中不起作用。如果您将其放在cron脚本(如/etc/cron.daily/)中,那么您只需#/在顶部的bin/bash。但是,如果您将它作为一个单行程序放在crontab中,那么您可能需要将它包装在bash-c“

中,不知道为什么没有人提到这一点

如果在用户crontab中指定MAILTO=,则使用CRON, STDOUT已经通过邮件发送

范例

[temp]$ sudo crontab -u user1 -l
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=user1
# transfer order shipping file every 3 minutes past the quarter hour
3,19,33,48 * * * * /home/user1/.bin/trans.sh

您可以尝试编写另一个cronjob来读取日志文件并“显示”日志(实际上只要让cron通过电子邮件发送给您即可)

除非我遗漏了什么:

command 2>&1 >> file.log | tee -a file.log
2> &1将stderr重定向到stdout

>>将常规命令stdout重定向到日志文件

|tee将stderr(从2>&1)复制到日志文件,并将其传递到stdout,然后由cron将其邮寄到MAILTO

我试了一下

(echo Hello & echo 1>&2 World) 2>&1 >> x | tee -a x
这确实显示了控制台中的世界和x中的两个文本

丑陋的是重复的文件名。与stdout/stderr不同的缓冲可能会使file.log中的文本有点混乱。

我的经验(ubuntu)是“crontab”只发送“stderr”电子邮件(我将输出定向到日志文件,然后归档)。这很有用,但我想确认脚本是否运行(即使“stderr”没有错误),以及脚本运行所需时间的一些细节,我发现这是发现潜在问题的好方法

我发现最容易解决这个问题的方法是编写脚本,其中包含一些重复的“echo”。扩展的常规“echo”最终出现在日志文件中。对于我的crontab'MAILTO'电子邮件中需要的重要非错误位,我使用了一个指向stderr的'echo',带有'1>&2'

因此:

    Frmt_s="+>>%y%m%d %H%M%S($HOSTNAME): " # =Format of timestamp: "<YYMMDD HHMMSS>(<machine name>): "
    echo `date "$Frmt_s"`"'$0' started." # '$0' is path & filename
    echo `date "$Frmt_s"`"'$0' started."  1>&2 # message to stderr

# REPORT:
    echo ""
    echo "================================================"
    echo "================================================" 1>&2 # message to stderr
    TotalMins_i=$(( TotalSecs_i / 60 )) # calculate elapsed mins
    RemainderSecs_i=$(( TotalSecs_i-(TotalMins_i*60) ))
    Title_s="TOTAL run time"
    Summary_s=$Summary_s$'\n'$(printf "%-20s%3s:%02d" "$Title_s" $TotalMins_i $RemainderSecs_i)
    echo "$Summary_s"
    echo "$Summary_s" 1>&2 # message to stderr
    echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
    echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 1>&2 # message to stderr
    echo ""
    echo `date "$Frmt_s"`"TotalSecs_i: $TotalSecs_i"
    echo `date "$Frmt_s"`"'$0' concluded." # '$0' is path & filename
    echo `date "$Frmt_s"`"'$0' concluded."  1>&2 # message to stderr

这并不能满足我最初希望“将stdout和stderr都发送到日志文件”(stderr,只有带有“1>&2”的“echo”行进入电子邮件;stdout进入日志),但我发现这比我最初设想的解决方案要好,由于电子邮件找到了我,我不必在日志文件中查找问题。

我认为解决方案是:

$SP_s/StartDailyS1.sh 2>&1 >> $LP_s/MirrorLogS1.txt | tee -a $LP_s/MirrorLogS1.txt
这将:

  • 将标准输出附加到
    $LP_s/MirrorLogS1.txt
  • 将标准错误附加到
    $LP_s/MirrorLogS1.txt
  • 打印标准错误,以便
    cron
    在出现错误时发送邮件

谢谢“不”,我看到了这个,它的目的是“将一个命令中的STDOUT和STDERR发送到一个文件,然后将STDERR发送到另一个文件”,zazzybob在unix.com上发布:((my_command 3>&1 1>&2>&3)| tee error_only.log)>all.log 2>&1它与您的建议和我想做的事情非常相似(除了我希望cron将STDERR发送到电子邮件,而不是“另一个文件”)。不幸的是,我没有足够的知识来根据我的需要修改它。这会激发任何想法吗?干杯,Stephen上面的内容将stdout和STDERR发送到一个文件,并且还将STDERR发送到stdout(因此,如果您运行cron作业,它将被发送)。因此,STDERR会进入您的邮件中。(我不知道如何将stdout/err只发送到一个文件,而不是上面提到的2个文件-并且仍然只发送stderr到邮件)这是一个很好的解决方案。我看到的唯一缺陷是每次都会覆盖日志文件。应该使用
>all.log
进行追加。
    Frmt_s="+>>%y%m%d %H%M%S($HOSTNAME): " # =Format of timestamp: "<YYMMDD HHMMSS>(<machine name>): "
    echo `date "$Frmt_s"`"'$0' started." # '$0' is path & filename
    echo `date "$Frmt_s"`"'$0' started."  1>&2 # message to stderr

# REPORT:
    echo ""
    echo "================================================"
    echo "================================================" 1>&2 # message to stderr
    TotalMins_i=$(( TotalSecs_i / 60 )) # calculate elapsed mins
    RemainderSecs_i=$(( TotalSecs_i-(TotalMins_i*60) ))
    Title_s="TOTAL run time"
    Summary_s=$Summary_s$'\n'$(printf "%-20s%3s:%02d" "$Title_s" $TotalMins_i $RemainderSecs_i)
    echo "$Summary_s"
    echo "$Summary_s" 1>&2 # message to stderr
    echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
    echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 1>&2 # message to stderr
    echo ""
    echo `date "$Frmt_s"`"TotalSecs_i: $TotalSecs_i"
    echo `date "$Frmt_s"`"'$0' concluded." # '$0' is path & filename
    echo `date "$Frmt_s"`"'$0' concluded."  1>&2 # message to stderr
170408 030001(sb03): '/mnt/data1/LoSR/backup_losr_to_elwd.sh' started.
ssh: connect to host 000.000.000.000 port 0000: Connection timed out
rsync: connection unexpectedly closed (0 bytes received so far) [Receiver]
rsync error: unexplained error (code 255) at io.c(226) [Receiver=3.1.0]
ssh: connect to host 000.000.000.000 port 0000: Connection timed out
rsync: connection unexpectedly closed (0 bytes received so far) [Receiver]
rsync error: unexplained error (code 255) at io.c(226) [Receiver=3.1.0]
================================================
S6 SUMMARY (mins:secs):
'Templates'           2:07
'Clients'             2:08
'Backups'             0:10
'Homes'               0:02
'NetAppsS6'          10:19
'TemplatesNew'        0:01
'S6Www'               0:02
'Aabak'               4:44
'Aaldf'               0:01
'ateam.ldf'           0:01
'Aa50Ini'             0:02
'Aadmin50Ini'         0:01
'GenerateTemplates'   0:01
'BackupScripts'       0:01
TOTAL run time       19:40
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
170408 031941(sb03): '/mnt/data1/LoSR/backup_losr_to_elwd.sh' concluded.
$SP_s/StartDailyS1.sh 2>&1 >> $LP_s/MirrorLogS1.txt | tee -a $LP_s/MirrorLogS1.txt