Search code examples
linuxbashterminalstdoutstderr

Bash script. During execution - stdout + stderr in terminal, also stdout + stderr to file and again stderr to another file. Is that even possible?


I have written multi-os provisioning script for local and aws ec2 VMs.

I want to achieve this behaviour of the script:

  1. Execution
  2. It shows stdout and stderr in terminal during execution
  3. Simultaneously it records all stdout + stderr to provision-full.log
  4. And also records all stderr to another file provision-err.log

Is that possible at all? I have googled a lot for the solution with no success. Am I miss something? I mean, maybe it's impossible to do by system design :)

The provision script has this design:

#!/bin/bash
# defining functions
{
  # some script here
} |& tee ~/full-provision.log

The closest solutions that I have been able to achieve:

  1. |& tee ~/full-provision.log for local VMs, so I could see output in terminal and later I'm able to inspect full-provision.log
  2. 2> /var/log/provision-err.log > /var/log/provision-out.log for aws ec2 VMs with 2 separate log files for inspection.

Solution

  • Duplicate standard error by redirecting it to process substitution tee /var/log/provision-err.log:

    { { # some script here } 2> >(tee /var/log/provision-err.log 1>&2); } |&
      tee ~/full-provision.log
    

    The only subtlety is that the standard output of the process substitution shall be redirected back to the standard error (1>&2) if we want to preserve the separation between standard output and standard error. If you don't care the following shall work about the same:

    { { # some script here } 2> >(tee /var/log/provision-err.log); } |
      tee ~/full-provision.log
    

    Note that this works only if your OS supports named pipes.