如何收集程序的日志和输出并将它们传递给函数的参数

How to collect the logs and output from a program and pass them into the parameter of a function

我有一个 shell 脚本,它具有记录语句的功能

#!/bin/sh

Log() {
    echo  >> /some/logfile
}

Log "Test logging works"

效果很好!

接下来,我有一个记录语句的程序,如果我想将那里的日志添加到文件中,我可以这样做

SomeProgram >> SomeFile.txt

这也很好用!

但是,如果我想在从同一个 shell 脚本调用 SomeProgram 的同时将日志从 SomeProgram 传递到我的函数 Log 中怎么办?那可能吗?以下是我尝试过但没有用的一些技巧。

Log "SomeProgram >> SomeFile.txt"
Log(SomeProgram >> SomeFile.txt)

问题
那么,如何从程序中收集日志并将它们传递到函数的参数中呢?

环境:
Linux

使用tee拆分输出

Log "$(SomeProgram | tee -a SomeFile.txt)"

解释:

SomeProgram | teeSomeProgram 的 stdio 输出传递给 tee 命令

tee -a SomeFile.txt会输出到stdio同时-a加到SomeFile.txt

Log "$(......)" 将捕获括号内命令的 stdio,并将结果作为参数传递给 Log 函数。

您可以编写一个函数来处理标准输入以及任何参数:

Log() {
  # if STDIN (0) is not a terminal, iterate over any lines of standard input
  [[ ! -t 0 ]] && while read line; do echo "$line" >> /some/logfile; done

  # iterate over any arguments provided
  for arg; do echo "$arg" >> /some/logfile; done
}

如果您有一个连续输出文本行的程序,您可以通过管道 | 该程序的标准输出到您函数的标准输入,手动输入参数,或两者兼而有之!

SomeProgram | Log
Log "line one" "line two"
SomeProgram | Log "additional line one" "additional line two"

查看 man bash/^ *Compound Commands 以了解适用于函数的所有语法类型。

如果是一次性的,我会写一个循环。

SomeProgram | while IFS= read -r line; do
    Log "$line"
done

如果你要经常这样做,你可以向 Log 添加第二种模式,它从标准输入而不是它的参数读取。

Log() {
    case  in
        --stdin)
            while IFS= read -r line; do Log -- "$line"; done
            return;;

        --)
            shift;;
    esac

    echo "$*" >> /some/logfile
done
SomeProgram | Log --stdin

不要!这样做会导致 Log() 在您的脚本被调用时消耗标准输入 non-interactively。好的脚本在自动化和在管道中使用时表现良好;他们不坚持键盘输入。