How to prefix any output in a bash script?

When a script runs, commands in it may output some text to stdout/stderr. Bash itself may also output some text.

But if a few scripts are running at the same time, it is hard to identify where does an error come from.

So is it possible to insert a prefix to all output of the script? Something like:

#!/bin/bash
prefix 'PREFIX' &2
echo "wrong!" >&2

Then:

$ ./script.sh
PREFIXwrong!

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

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.

Method 2

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/…

Method 3

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
    "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="082c48">[email protected]</a>" > >(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##*/}"
    "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6f4b2f">[email protected]</a>" > >(sed "s/^/$prefix: /") 2> >(sed "s/^/$prefix (err): /" >&2)
}
prefixoutput ./script.sh


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x