将 ssh 的输出(stderr 和 stdout)通过管道传输到不同的命令

将 ssh 的输出(stderr 和 stdout)通过管道传输到不同的命令

我正在编写涉及 ssh 和 rsync 的某种备份的脚本。每次运行该脚本时,我都会将所有输出重定向到日志文件。为了标准化日志条目,我编写了一个添加时间戳和日志级别的日志函数。我的想法是还逐行读取每个命令行的 stdout 和 stderr 并调用该日志函​​数。因此我遵循了以下答案https://serverfault.com/questions/526592/pipe-stderr-and-stdout-to- Different-commands-not-just-to-files

我的脚本如下所示(它有所减少,假设所有使用的变量都设置正确):

#!/bin/bash

# function: print a formatted log message including timestamp with given level and message to stdout 
# arguments: <LEVEL> <MESSAGE>
log()
{
    timestamp=$(date +"%F %T.%3N")
    level=$1
    message=$2
    echo $timestamp $level: $message
}

# function: read command output from stdin and log it with given level
# arguments: <LEVEL>
logoutput()
{
    sed 1d | \
    while read i
    do
        log "$1" "$i"
    done
}

log INFO "START ssh"
(ssh $connection mkdir -p $destStaticDirectory | logoutput INFO) 3>&1 1>&2 2>&3 | logoutput ERROR

log INFO "START rsync"
(rsync $rsyncArguments $linkDest $fromDirectory $connection:$destStaticDirectory | logoutput INFO) 3>&1 1>&2 2>&3 | logoutput ERROR

该函数log()用于回显日志条目,该函数logoutput()用于stdout逐行读取并记录每行。

现在事情是一切都按 rsync 命令的预期工作。但不适用于 ssh 命令。我知道ssh $connection mkdir -p $destStaticDirectory正确调用时没有输出到标准输出。所以我通过让 ssh 连接到一个未知的主机来测试它,结果是ssh: Could not resolve hostname XXX: Name or service not known.但又什么也没有。我还在脚本中添加了相同的 ssh 命令“unwrapped”,该命令按预期打印所有输出。最后我打开了 ssh 的详细模式,这导致了错误日志条目。但这不是一个选项,因为我不希望 ssh 的 bug 消息出现在我的日志中。

我错过了什么吗?是否有我不知道的相同奇怪的 stdout,err 处理 ssh 正在做的事情?我希望我清楚地表达了我要做什么。

答案1

您的问题很可能出现在 logoutput 函数中,其中“sed 1d”删除了您正在查找的输出。尝试删除“sed 1d”行并查看脚本是否按预期运行。

答案2

您是否考虑过使用记录器(1)为您进行日志记录并添加时间戳等。

然后像

{ ssh ... | logger ...; }  2>&1 | logger ...

应该是你想要的,因为第一部分通过记录器将stdout发送到日志文件,第二部分将stderr发送到日志文件。您可以使用记录器命令行选项来选择哪个日志设施或文件等。


还有一种更简洁的方法可以做到这一点。使用流程替代例如

ssh ... > >(logger ...) 2> >(logger ...)

这样就不必再混乱地处理所有文件描述符了。

相关内容