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

Viewed 905

I have a shell script which has a function to Log statements

#!/bin/sh

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

Log "Test logging works"

This works great!

Next, I have a program which logs statements and if I want to have the logs from there added into a file, I can do like this

SomeProgram >> SomeFile.txt

This also works great!

But, what if I want to pass the logs from SomeProgram into my function Log while calling SomeProgram from the same shell script. Is that possible? Following are some tricks I tried which didn't work.

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

Question
So, how can I collect the logs from a program and keep passing them into the parameter of a function?

Environment:
Linux

3 Answers

If it's a one off case I'd write a loop.

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

If you're going to be doing it a lot you could add a second mode to Log where it reads from stdin instead of its arguments.

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

        --)
            shift;;
    esac

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

Do not check if stdin is a tty! Doing so would cause Log() to consume stdin any time your script is called non-interactively. Good scripts behave well when automated and used in pipelines; they don't insist on keyboard input.

You can write a function which will handle standard input as well as any arguments:

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
}

If you have a program that will continuously output lines of text, you can pipe | that program's standard output to your function's standard input, feed it arguments manually, or both!

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

Check out man bash, /^ *Compound Commands for all types of syntax that will work with functions.

use tee to split output

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

Explanation:

SomeProgram | tee pass the stdio output from SomeProgram to the tee command

tee -a SomeFile.txt will output to stdio and at the same time -a add to SomeFile.txt

Log "$(......)" will capture stdio of commands inside the parenthesis and pass the result as parameter to the Log function.

Related