如何让 Linux 上的 SCP 将“成功”输出到 stdout 而不是 stderr?

如何让 Linux 上的 SCP 将“成功”输出到 stdout 而不是 stderr?

我们有一个 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实际上会转到STDERRSTDERR实际上会转到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 电子邮件。

相关内容