我们有一个 cron 作业,使用 SCP 将东西发送到另一家公司。命令如下:
10 0 * * * ssh USER@LOCAL-SERVER 'scp -q ~/some/dir/* REMOTE_SERVER:/other/dir/' >> ~/log/some.log
这是别人设置的。现在我的问题是我的老板在 cron 邮件列表中,尽管有“>> ~/log/some.log”,cron 仍然每天发送电子邮件,因为即使传输成功,它仍然会输出:
Connection to REMOTE_SERVER 12345 port [tcp/*] succeeded!
除非发生错误,否则我的老板不想收到该电子邮件。
该命令实际上位于脚本中,我省略了该脚本以使问题更简单。它在 RHEL 6 服务器上运行。但由于这是我们与 REMOTE_SERVER 对话的唯一线路,因此它必须来自那里。我们在 LOCAL-SERVER(Ubuntu 10.04.4 LTS)上执行命令的原因是我们在无法跨越防火墙的 DB 服务器上,因此我们首先将数据复制到另一台本地服务器,然后从那里上传。
当不带 -q 使用时,我也会得到以下输出:
SSH Server supporting SFTP and SCP
我不想重定向所有 stderr 输出,因为我仍然希望在出现错误时收到电子邮件。
答案1
我认为您无法STDERR
选择性地重定向输出,除非重写程序以将这些特定消息写入STDOUT
而不是STDERR
。但是,您可以编写一个包装器脚本来过滤掉不需要的消息,然后在作业中运行该脚本cron
。
#!/bin/bash
(ssh USER@LOCAL-SERVER ... 3>&1 1>&2- 2>&3-) 2>> ~/log/some.log \
| grep -v "Connection .* succeeded" 1>&2
exit $?
出于好奇,为什么您不直接在 LOCAL-SERVER 上cron
使用命令运行作业?scp
编辑:STDERR
您想在将所有输出重定向到文件的同时过滤掉部分输出STDOUT
,但管道可以连接STDOUT
一个进程到STDIN
另一个进程。|&
或者2>&1 |
将不起作用,因为STDOUT
已经被重定向到~/log/some.log
,所以没有任何内容进入管道,并且日志文件中会出现大量不需要的输出。
但是,可以交换描述符,这样STDOUT
实际上会转到STDERR
,STDERR
实际上会转到STDOUT
。然后,您可以将所有STDERR
输出重定向到日志文件,并STDOUT
通过 过滤输出grep
。有人在堆栈溢出发布了这个巧妙的小技巧。1>&2
将过滤后的输出返回给STDERR
。
答案2
假设你正在使用 BASH:
通过首先放置重复项来交换 stdout 和 stderr:
2>&1 >> ~/log/some.log ssh USER@LOCAL-SERVER'scp -q ~/some/dir/* REMOTE_SERVER:/other/dir/'
然后设置一个管道来获取发送到 stderr 的任何内容:
2>&1 >> ~/log/some.log ssh USER@LOCAL-SERVER'scp -q ~/some/dir/* REMOTE_SERVER:/other/dir/'|
并且仅针对失败消息进行 grep:
2>&1 >> ~/log/some.log ssh USER@LOCAL-SERVER 'scp -q ~/some/dir/* REMOTE_SERVER:/other/dir/' | grep -E "失败消息"
这将生成 cron 抓取并包含在其 MAIL 消息中的输出。所有其他“stderr”输出将消失(丢失)。如果出于某种原因您想保存所有 stderr 的副本,请先使用 tee 命令:
2>&1 >> ~/log/some.log ssh USER@LOCAL-SERVER 'scp -q ~/some/dir/* REMOTE_SERVER:/other/dir/' | tee -a ~/log/some_other.log | grep -E "失败消息"
这会将所有 stderr 的副本放入新的日志文件中,然后只有失败消息才会进入 CRON 电子邮件。