#!/bin/sh # Example of duplicating STDOUT+STDERR into a log file # Copyright (C) 2016 Assaf Gordon # License: MIT # # This script demonstate how to setup logging of all STDOUT and STDERR # outputs into a log file (in addition to also outputing it to the # original STDOUT/STDERR (e.g. the terminal). # # The function 'setup_logging1' MERGES stdout and stderr into one log file. # This makes it easier to review later, but loses the distinction between # what was printed to STDOUT and what was printed to STDERR. # depending on your application, this might be acceptable. # # See 'log-to-file2.sh' for an alternative (saving STDOUT and STDERR into # two separate files). die() { BASE=$(basename "$0") echo "$BASE: error: $@" >&2 exit 1 } setup_logging1() { logfile="$1" test -z "$logfile" \ && die "internal error: missing log filename parameter" # Create a tmp directory, to store the fifo __pipedir=$(mktemp -d -t log.XXXXXX) \ || die "failed to create tmp directory" # Create the fifo file mkfifo "${__pipedir}/log-fifo" \ || die "failed to create fifo" # Run 'tee' in the background, duplicating # the input (from the fifo) to both STDOUT and the log file tee "$logfile" < "${__pipedir}/log-fifo" & # Re-exec this shell instance, merging STDERR into STDOUT # and redirecting STDOUT into the fifo exec >"${__pipedir}/log-fifo" 2>&1 # Delete the FIFO and the temp dir - # no harm since the the fifo's file-descriptior is # held open by 'tee'. Saves the trouble of cleanup on exit. rm "${__pipedir}/log-fifo" \ || die "failed to cleanup fifo file" rmdir "${__pipedir}" \ || die "failed to cleanup tmp dir" } # Setup logging into a file with a time stamp log=program-$(date +%F-%H%M%S).log setup_logging1 "$log" # Simulate some output both to STDOUT and STDERR echo "Logging Example - anything you see printed to the terminal" echo " is also saved in the file '$log'" echo "Hello (Stdout)" echo "Hello (stderr)" >&2 # Simulate potential error messages to stderr echo "Trying to copy non-existing file (which will fail):" cp "/foo/bar" "/bar/baz"