2

I'm currently having an issue getting echo statements in my trap function to be printed to stdout. I'm redirecting all output (error and stdout) to a log file from a command that I run. But if it hits an error, I want the error redirected back to stdout instead of the log file.

I was thinking of just doing something like trap 1> on_exit EXIT. But I have no idea on that. How should I do this?

Edit: As a clarification, I am purposely redirecting ALL output (stderr and stdout) to a log file. If at ANY point there is an error, the output of that error of that command is put in the log (Which Is What I Want), AND I want the the on_exit function output to the user's view (stdout) instead of the log file. My script currently has that trap function outputting to the log file. I just want it sent to stdout.

#!/usr/bin/env bash
set -e

on_exit()
{
  echo "An error occurred"
}

function main()
{
  trap on_exit EXIT
  # for looping over set of commands
  $command &> "$LOGFILE"
}

main "$@"
  • how is "an error" identified? specific text on stdout, or anything on stderr, or something else? – Jeff Schaller Jun 4 '19 at 17:14
  • Just if the command returns 1 from it. I'm doing a lot of cmake/make stuff, so if an error happens during that command the trap will catch it. – pianoman102 Jun 4 '19 at 17:15
  • It is not clear what's the problem with your script. Maybe you should also show (parts of) your real script to make the problem more clear. If $command exits, the redirection will no longer be valid. Even if you redirected stdout or stderr for the whole script, this will not affect the parent process when the shell exits. For me it is not clear which output would need stdout or stderr to be restored. Or is it simply that you might want to use trap on_exit ERR instead of trap on_exit EXIT? – Bodo Jun 4 '19 at 17:30
  • That's a good question. The script I have is very long, so I've cut it down quite a bit for brevity's sake. The $command is from my comment stating that I have a for loop looping over an array of commands, which are just functions within the script. Bottom line is, I'm outputting stdout and stderr to a file when I'm executing these functions. But at any given point during the execution of a particular function that an error occurs, the function called on the trap has its output sent to the log file as well. I want it sent to the the user's view. Hopefully that makes more sense. – pianoman102 Jun 4 '19 at 17:34
  • Hang on, if you don't want stderr to go to the log file, then why are you redirecting both? Or do you only want the very last error message to be sent to stdout and anything else printed to stderr should be sent to the logfile? – terdon Jun 4 '19 at 17:35
0

[this is more a comment than an answer; it's not really clear what you're trying to achieve]

The set -e will cause your script to exit upon an error, so it's just too late to redirect anything.

Maybe you're after something like this:

#! /bin/bash
set -o errtrace # let functions inherit the ERR trap
exec 3>&2       # save the original stderr into fd 3

on_error() {
        echo >&2 "An error occurred"    # still printed to the log the 1st time
        exec 2>&3       # switch back to the original stderr
        trap '' ERR     # disable ourselves
}
main() {
        trap on_error ERR
        no_such_command # this fail with an error
        no_such_command # again
        no_such_command # and again
}

main "$@" >/tmp/log 2>&1

when running it:

$ bash /tmp/err
/tmp/err: line 13: no_such_command: command not found
/tmp/err: line 14: no_such_command: command not found
$ cat /tmp/log
/tmp/err: line 12: no_such_command: command not found
An error occurred

OP's script modified to print a message to the original stderr and exit upon an error:

#!/usr/bin/env bash
set -o errtrace # let functions inherit the ERR trap
exec 3>&2       # save the original stderr

on_error()
{
  echo >&3 "An error occurred"
  exit 1
}

function main()
{
  trap on_error ERR
  # for looping over set of commands
  $command &> "$LOGFILE"
}

main "$@"

when running it:

$ command=no_such_command LOGFILE=/tmp/log bash /tmp/jeg
An error occurred
$ cat /tmp/log
/tmp/jeg: line 15: no_such_command: command not found
  • Thanks for your answer, I was looking for something a little simpler, would there be another way that's more align with what I have? I clarified my question also. – pianoman102 Jun 4 '19 at 18:29
  • If you want just to have the "An error occurred" printed to the original stderr, keep the set -o errtrace and exec 3>&2 at the beginning, and change your on_error trap to just echo >&3 "An error ocurred", (notice the 3 instead of 2), and remove the stderr switch-back and trap disabling. If you really want that message to go to the user's original stdout, not stderr, use exec 3>&1 instead of exec 3>&2, etc. – mosvy Jun 4 '19 at 18:36
  • Actually, in testing this, any error that happens is not caught by trap. The script continues to run after an error occurs. It only reports that errors happened at the end of the script. – pianoman102 Jun 4 '19 at 19:05
  • If the errors weren't caught, then the An error ocurred wouldn't have been printed ever, not at the end of the script. If you're piping the output of your script to another filter or such take care with the buffering. For instance { echo >&2 error; echo >&2 error; sleep 10; } 2>&1 | sed s/e/E/ | cat will only print the 2 Error messages after 10 seconds. – mosvy Jun 4 '19 at 19:29
  • I must not be understanding then. Previously, in my initial post of the script, any error that occurred was caught and the script exited. The only thing that was NOT happening was the function on_exit was not getting output to stderr or stdout, it was redirected to the logfile. How do I get that to happen without introducing other functionality to the script? – pianoman102 Jun 4 '19 at 19:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.