How to prefix any output in a bash script?
You can redirect stderr/stdout to a process substitution that adds the prefix of choice. For example, this script:
#! /bin/bash
exec > >(trap "" INT TERM; sed 's/^/foo: /')
exec 2> >(trap "" INT TERM; sed 's/^/foo: (stderr) /' >&2)
echo foo
echo bar >&2
date
Produces this output:
foo: foo
foo: (stderr) bar
foo: Fri Apr 27 20:04:34 IST 2018
The first two lines redirect stdout and stderr respectively to sed commands that add foo:
and foo: (stderr)
to the input.
The calls to the shell built-in command trap
make sure that the subshell does not exit when terminating the script with Ctrl+C
or by sending the SIGTERM
signal using kill $pid
. This ensures that your shell won't forcefully terminate your script because the stdout
file descriptor disappears when sed
exits because it received the termination signal as well. Effectively you can still use exit traps in your main script and sed
will still be running to process any output generated while running your exit traps. The subshell should still exit after your main script ends so sed
process won't be left running forever.
You could pipe the output through some way of replacing lines:
some long running stuff | sed -e 's/^/Some said: /;'
Also check 24337
Or just direct separate outputs to separate files/screen(1) tabs/tabs in your terminal/...
One option in bash is to do this by redirecting to process substitutions, something like this:
./script.sh > >(sed 's/^/script: /') 2> >(sed 's/^/script (err): /' >&2)
This has the problem that output may be out of order (as Charles Duffy mentioned in a comment). It's also really annoyingly unweildy. But you could make a wrapper function for it:
prefixwith() {
local prefix="$1"
shift
"$@" > >(sed "s/^/$prefix: /") 2> >(sed "s/^/$prefix (err): /" >&2)
}
prefixwith "From script" ./script.sh
Or make it even simpler by having it use the command name as a prefix:
prefixoutput() {
local prefix="From ${1##*/}"
"$@" > >(sed "s/^/$prefix: /") 2> >(sed "s/^/$prefix (err): /" >&2)
}
prefixoutput ./script.sh