How can I fully log all bash scripts actions?

Solution 1:

I generally put something similar to the following at the beginning of every script (especially if it'll run as a daemon):

#!/bin/bash
exec 3>&1 4>&2
trap 'exec 2>&4 1>&3' 0 1 2 3
exec 1>log.out 2>&1
# Everything below will go to the file 'log.out':

Explanation:

  1. exec 3>&1 4>&2

    Saves file descriptors so they can be restored to whatever they were before redirection or used themselves to output to whatever they were before the following redirect.

  2. trap 'exec 2>&4 1>&3' 0 1 2 3

    Restore file descriptors for particular signals. Not generally necessary since they should be restored when the sub-shell exits.

  3. exec 1>log.out 2>&1

    Redirect stdout to file log.out then redirect stderr to stdout. Note that the order is important when you want them going to the same file. stdout must be redirected before stderr is redirected to stdout.

From then on, to see output on the console (maybe), you can simply redirect to &3. For example,

echo "$(date) : part 1 - start" >&3

will go to wherever stdout was directed, presumably the console, prior to executing line 3 above.

Solution 2:

to get the ssh output to your logfile, you have to redirect stderr to stdout. you can do this by appending 2>&1 after your bash script.

it should look like this:

#!/bin/bash
(
...
) 2>&1 | tee ...

when this does not display the mesages in the right order, try to add another subshell:

#!/bin/bash
((
...
) 2>&1) | tee ...

Solution 3:

As I read your question, you don't want to log the output, but the entire sequence of commands, in which case, the other answers won't help you.

Invoke shell scripts with -x to output everything:

sh -x foo.sh

Log to the file you want with:

sh -x foo.sh >> /home/scripts/cron/logs


Solution 4:

In bash, you can put set -x and it will print off every command that it executes (and the bash variables) after that. You can turn it off with set +x.

If you want to be paranoid, you can put set -o errexit in your script. This means the script will fail and stop if one command returned a non-zero exit code, which is the unix standard way to signal that something went wrong.

If you want to get nicer logs, you should look at ts in the moreutils debian/ubuntu package. It will prefix each line with a timestamp and print it out. So you can see when things were happening.


Solution 5:

Following off of what others said, the set manual is a good resource. I put:

#!/usr/bin/env bash
exec 1> command.log 2>&1
set -x

At the top of scripts I wish to keep going, or set -ex if it should exit upon error.