Bilal Chughtai
Bilal Chughtai

Reputation: 63

Prompt not printed after redirecting bash script output to syslog

I found this article, that explains how to redirect output of a bash script to syslog. This is exactly what I needed, but there is a problem.

#!/bin/bash

# Don't ignore any error and return when first error occurs.
exec 1> >(logger -s -t $(basename $0)) 2>&1
set -e  

# a list of command(s) that can fail:
chown -R user1:user1 /tmp/myappData/* 
chown -R user1:user1 /tmp/myappTmp/* 
chown -R user1:user1 /tmp/myappLog/* 
#...

exit 0

When I execute above script, and an error occurs, I see that sometimes, the prompt doesn't return after the script is executed. I can't figure out why this is happening. The prompt doesn't return unless I hit enter.

I am concerned that if an app uses this script, it may not get proper exit code back.

If I comment out "set -e", then the prompt always returns properly after the script has executed.

So my question is, what is the proper way to setup a script so that it exits on error, and logs the corresponding message to syslog?

Thank you for your help and suggestions!

Upvotes: 1

Views: 373

Answers (1)

Charles Duffy
Charles Duffy

Reputation: 295678

The problem here is that the logger pipeline is still running after your script exits, so some of the last content to be logged print after the parent shell has emitted its prompt. If you scroll up, you'll find the prompt hidden somewhere in that prior output.


If you have a very, very new bash, you can collect the PID of the process substitution, and wait for it later.

exec {orig_out}>&1 {orig_err}>&2 1> >(logger -s -t "${0##*/}") 2>&1; logger_pid=$!
[[ $logger_pid ]] || { echo "ERROR: Needs a newer bash" >&2; exit 1; }

cleanup() {
  exec >&$orig_out 2>&$orig_err
  wait "$logger_pid"
}
trap cleanup EXIT

With an older bash, you can consider other tricks. For example, on Linux, you can use the flock command to try to grab exclusive access to a lockfile before exiting, after ensuring that that lock is held for as long as the logger is running:

log_lock=$(mktemp "${TMPDIR:-/tmp}/logger.XXXXXX")
exec >(flock -x "$log_lock" logger -s -t "${0##*/}") 2>&1

cleanup() {
  exec >/dev/tty 2>&1 || exec >/dev/null 2>&1
  flock -x "$log_lock" true
}
trap cleanup EXIT

Upvotes: 2

Related Questions