2

I was looking for a way to route the output of my shell scripts to syslog, and found this article, which suggests putting the following line at the top of the script:

exec 1> >(logger -s -t $(basename $0)) 2>&1

I've tried this with the following simple script:

#!/bin/bash
exec 1> >(logger -s -t $(basename $0)) 2>&1
echo "testing"
exit 0

When I run this script from the shell, I do indeed get the message in the syslog, but the script doesn't seem to return--in order to continue interacting with the shell, I need to hit Enter or send a SIGINT signal. What's going on here? FWIW, I'm mostly using this to log the results of cron jobs, so in the wild I probably don't need it to work properly in an interactive shell session, but I'm nervous using something I don't really understand in production. I am mostly worried about spawning a bunch of processes that don't terminate cleanly.

I've tested this on Ubuntu 15.10, Ubuntu 16.04, and OSX, all with the same result.

6
  • 1
    Given the symptoms you describe, what's going on is that Bash isn't exiting until all its child processes exit. You could try exec >/dev/null 2>&1 before exit 0 to see if that stops the logger — basically, the redirection closes its inputs, so it should terminate, allowing the script to exit. However, when I try your script (bash logtest.sh) on macOS Sierra 10.12.2 (though I'd not expect it to change in earlier versions), the command exits promptly and produces a log message on the terminal like Dec 26 12:23:50 logtest.sh[6623] <Notice>: testing. This arrived after the prompt. Commented Dec 26, 2016 at 20:27
  • @JonathanLeffler You are right--I had an error in my question. Any key will return to the bash prompt--not just a SIGTERM signal. However, it still behaves differently than a plain echo, which just prints and exits. exec >/dev/null 2>&1 didn't seem to change anything. Commented Dec 26, 2016 at 20:59
  • 1
    When I ran bash logtest.sh (where logtest.sh contained your script), the only key I hit was the return to enter the command (which the shell read before running the command). I then got a prompt, the output from logger, and a blank line with the terminal waiting for input. That's normal. The logger was not still running — I could check that in other windows. Commented Dec 26, 2016 at 21:04
  • Interesting. Why does it wait for a keystroke before returning to the bash prompt with the logging line at the top? If I comment out the top line and run the script, I get "testing" in stdout and then the terminal immediately returns to the bash prompt (nrlakin@mycpu$). With that line, I need to hit a key before it jumps back. At this point I'm just curious; if you want to summarize your comments above as an answer, I'll accept it. Commented Dec 26, 2016 at 21:24
  • 1
    Try typing ls instead of just hitting return. The shell is waiting for input. It wrote its prompt, but the logger output confused the on-screen layout. For me, I use a prompt Osiris JL: followed by a space, and I typed: Osiris JL: bash logtest.shOsiris JL: Dec 26 13:03:33 logtest.sh[6910] <Notice>: testingblank line — and I hit return to get another prompt, but I could type ls instead and get a directory listing, etc. Osiris JL: Commented Dec 26, 2016 at 21:28

1 Answer 1

2

Cutting a long story short: the shell script does exit and so does the logger — there isn't actually a problem — but the output from the logger lead to confusion.

Converting comments into an answer.

Superficially, given the symptoms you describe, what's going on is that Bash isn't exiting until all its child processes exit. You could try exec >/dev/null 2>&1 before exit 0 to see if that stops the logger — basically, the redirection closes its inputs, so it should terminate, allowing the script to exit.

However, when I try your script (bash logtest.sh) on macOS Sierra 10.12.2 (though I'd not expect it to change in earlier versions), the command exits promptly and produces a log message on the terminal like this (I use Osiris JL: as my prompt):

Osiris JL: bash logtest.sh
Osiris JL: Dec 26 12:23:50  logtest.sh[6623] <Notice>: testing

Osiris JL: ps
  PID TTY           TIME CMD
71792 ttys000    0:00.25 -bash
  534 ttys002    0:00.57 -bash
  543 ttys003    0:01.71 -bash
  558 ttys004    0:00.44 -bash
Osiris JL:

I hit return on the blank line and got the prompt before the ps command.

Note that the message from logger arrived after the prompt.

When I ran bash logtest.sh (where logtest.sh contained your script), the only key I hit was the return to enter the command (which the shell read before running the command). I then got a prompt, the output from logger, and a blank line with the terminal waiting for input. That's normal. The logger was not still running — I could check that in other windows.

Try typing ls instead of just hitting return. The shell is waiting for input. It wrote its prompt, but the logger output confused the on-screen layout. For me, I got:

Osiris JL: bash logtest.sh
Osiris JL: Dec 26 13:28:28  logtest.sh[7133] <Notice>: testing
ls
README.md               ix37.sql                mq13.c                  sh11.o
Safe                    lib                     mq13.dSYM               so-4018-8770
Untracked               ll89                    oddascevendesc          so-4018-8770.c
ci11                    ll89.cpp                oddascevendesc.c        so-4018-8770.dSYM
ci11.c                  ll89.dSYM               oddascevendesc.dSYM     sops
ci11.dSYM               ll97                    rav73                   src
data                    ll97.c                  rav73.c                 tf17
doc                     ll97.dSYM               rav73.dSYM              tf17.cpp
es.se-36764             logtest.sh              rd11                    tf17.dSYM
etc                     mac-clock-get-time      rd11.c                  tf19
fa37.sh                 mac-clock-get-time.c    rd11.dSYM               tf19.c
fileswap.sh             mac-clock-get-time.dSYM rn53                    tf19.dSYM
gm11                    makefile                rn53.c                  x-paste.c
gm11.c                  matrot13                rn53.dSYM               xc19
gm11.dSYM               matrot13.c              sh11                    xc19.c
inc                     matrot13.dSYM           sh11.c                  xc19.dSYM
infile                  mq13                    sh11.dSYM
Osiris JL:
Sign up to request clarification or add additional context in comments.

2 Comments

Have you considered waiting for the process? exec > >(...) 2>&1; loggerPID=$!; ...stuff...; exec >&- 2>&-; wait $loggerPID?
@gniourf_gniourf: not really, but in practice there isn't a problem — the question was raised because of a misunderstanding or misinterpretation of the output. The 'superficially' section turns out to be mostly a red herring — that's why it now starts 'superficially' where it didn't in the original comments. I think that, like the exec >/dev/null 2>&1 suggestion, your suggestion closing standard output and standard error would also work, and the wait would not be prolonged, but it also seems to be unnecessary. The original script is fine when you understand what you see on the terminal.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.