17

This question already has an answer here:

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!

marked as duplicate by Sergiy Kolodyazhnyy, Jesse_b, Isaac, G-Man, roaima Apr 28 '18 at 11:31

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 2
    How are you running multiple scripts at once? – Jesse_b Apr 27 '18 at 13:42
  • 3
    Could something like function echo() { /bin/echo $PREFIX$*; } help you? – Philippos Apr 27 '18 at 13:46
  • @Jesse_b by a parent script or something. The scripts are not depending on each other. So running in parallel saves some time. – Magicloud Apr 27 '18 at 14:37
  • @Philippos But this does not affect the command called in the script. Also, for example, [ x -eq 1 ] caused shell itself reporting error, which this kind of way could not help. – Magicloud Apr 27 '18 at 14:38
30

You can redirect stderr/stdout to a process substitution that adds the prefix of choice. For example, this script:

#! /bin/bash
exec > >(sed 's/^/foo: /')
exec 2> >(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.

  • 5
    Note that doing this one loses the guarantee that ordering will be consistent between the two streams -- if you write, say, five lines to stdout, one line to stderr, and five more lines to stdout, it's not at all guaranteed that the line written to stderr will have five stdout lines before it and five after it when it finally gets flushed. – Charles Duffy Apr 27 '18 at 19:54
  • @CharlesDuffy Do you have any extra information on that ? A couple links perhaps ? – Sergiy Kolodyazhnyy Apr 28 '18 at 1:47
  • @SergiyKolodyazhnyy I think the dupe candidate suggested by you and the possible dupe for that question are good for that - both have some discussion on retaining ordering of the output. – muru Apr 28 '18 at 3:39
5

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

  • 1
    This does not help with stderr. And my requirement is more like running in console at boot up, instead of terminal window. – Magicloud Apr 27 '18 at 14:39
0

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.