Bash: how to highlight executed commands?

628 Views Asked by At

Bash provides option -v --verbose which writes the command as it read to stderr.
Need to highlight this output. Current solution

bash -v script 2> >(sed $'s,.*,\e[38;5;123m&\e[m,' >&2)

highlight everything in stderr.

So the problem is to separate -v output from others stderr.

Addition. bash has BASH_XTRACEFD which can be used to highlight -x(xtrace) output.

Update: such kind of redirection also violates sequence of command/response - responses can appear before commands.
So the current solution is DO NOT highlight nothing at all.

Upd2.: It looks to be a good idea to use expect - programmed dialogue with interactive programs..

1

There are 1 best solutions below

3
On BEST ANSWER

EDIT:

What you are asking for is not possible:

  1. Without patching bash, it is not possible to dissociate bash's -v output from your program's stderr
  2. Even if that was possible, split outputs cannot be re-synchronized easily, so you would not be able to have every line colorized followed directly by its output.

The only way you could easily get what you want would be to

  1. Adapt your script so that each line can be individually sourced (is a valid bash command line)
  2. Create a wrapper script which reads your script line by line, and evals it after printing it colorized.

My original answer (kept below) uses a workaround which does what you want but with the caveat of grouping all the colorized output in one single block (and you want each line to be colorized as it is executed).

ORIGINAL:

Since there is currently no way of telling bash to use another descriptor for -v's output, so you can not separate it from your script's stderr.

If what you want to achieve is highlighting only -v's output (and not stderr), the only way you can achieve that would be to tweak your script to separate the streams manually:

  1. Add exec 2>&3 as the first instruction in your script,
  2. Wrap the rest of your code in a { ... ; } 2>&4 block
  3. Call bash -v newscript 3> >(sed $'s,.*,\e[38;5;123m&\e[m,' >&2) 4>&2

If you want a wrapper to do all that automatically, you can use this:

bash -v <(printf %s\\n 'exec 2>&3' '{'; cat script; printf %s\\n '' '} 2>&4') 3> >(sed $'s,.*,\e[38;5;123m&\e[m,' >&2) 4>&2

or if you're an echo fan:

bash -v <(echo $'exec 2>&3\n{'; cat script; echo $'\n} 2>&4') 3> >(sed $'s,.*,\e[38;5;123m&\e[m,' >&2) 4>&2
  • (note that the '' part in the second printf is to handle scripts which don't have a trailing newline)
  • Be sure to use other FDs than 3 and 4 is your script needs to use them