I would like a shell script to have all it's output for stdout and stderr logged to an external file with timestamps prepended to each line (plus a few extra items), without changing how the script is called. The output redirection should happen within the script itself. I also should not have to change any existing code in the script or pipe commands individually. Ideally I would only have to add a few lines to the script.

Using these two answers:

I got to a point where it's working on Bash

#! /usr/bin/env bash


touch $LOG_FILE
exec 1>> >(while IFS= read -r line; do printf '[%s] %s %s: %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "${CUSTOM_PREFIX1}" "${CUSTOM_PREFIX2}" "${line}"; done >> "${LOG_FILE}")
exec 2>&1

# Script continues...
echo "Hello"

Running the script above produces no output and the following log file:

# cat /var/log/script.log

[2022-02-23 03:11:45] FancyScript SomeRunID_12-3-4.5: Development/shell_log.sh: line 12: d: command not found
[2022-02-23 03:11:45] FancyScript SomeRunID_12-3-4.5: Hello

So far so good, but I want to change two things.

  1. Make it work in POSIX shell (sh) and not depend on Bash. Regular sh doesn't like exec 1>> >(...)
  2. Instead of that long sub process (while IFS= read ....) I want to pipe it to a function within the script itself. Something like pipe_log() {...}

3 Answers 3


I think logger is specifically written for this: writing to the syslog files.

See the logger(1) manual (man logger) and the link to the POSIX specification for that utility above for details.

  • This (logger) does the job perfectly. As a nice bonus I can use the OS's syslog to further manage it.
    – Tuaris
    Apr 8, 2022 at 7:09

The most advanced text processing utilities in the Unix toolchest are ex/vi, awk and m4, all from the 70s. None of them have time formatting abilities (though with POSIX awk, you can get the epoch time via srand(), and several implementations of awk or vi have time formatting abilities as extensions).

perl, from the mid-80s however is quite ubiquitous and POSIX didn't have to be involved with its standardisation given that there's only one implementation of it.

So you can always wrap your sh script in:


  your-script here

} 2>&1 | perl -MPOSIX -pse '
  $_ = strftime("[%Y-%m-%dT%T%z]", localtime) . " $prefix$_"
  ' -- '-|=1' "-prefix=$CUSTOM_PREFIX" >> /path/to/file.log

To timestamp every line.

Note the %z for those timestamps to be unambiguous and post-processable.

  • Any non-syslog native tool used to try to write to syslog will utimately corrupt the file.
    – JdeHaan
    Nov 11, 2022 at 18:07
  • @JdeHaan there's no mention of syslog in the question. Nov 11, 2022 at 18:53

The logger I mentioned above is intended for the older syslogging environments. On newer, systemd based systems, the systemd-cat utility is more appropriate:

echo 'my message' | systemd-cat -p info -t /path/to/script/executing/this
  • 1
    That is not about age. systemd is Linux-specific in any case. Nov 10, 2022 at 16:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .