How to insert tabs before output lines from a executed command

Solution 1:

You could do something like this - with file descriptors:

  1. save the current output descriptor so we can restore it later

    exec 3>&1
    
  2. redirect the output stream to a process substitution that inserts the tab - for example

    exec 1> >(paste /dev/null -)
    

From this point, any process that writes to standard output will have that output 'filtered' through the paste command to insert tabs at the start.

  1. When you're done, you can resume normal behavior by restoring the saved file descriptor and closing the temporary one

    exec 1>&3 3>&-
    

Solution 2:

I understand this answer is not optimal for you, but you could make a Bash function with the simple name like _ (or anything else that is not used yet) which runs the command it gets as arguments and indents all of its output with a tab.

An example:

$ _ lsb_release -a
    No LSB modules are available.
    Distributor ID: Ubuntu
    Description:    Ubuntu 16.04 LTS
    Release:    16.04
    Codename:   xenial

More complex shell constructs would be possible too, but need to be given as quoted argument or with special characters escaped to prevent evaluation before it was passed to the function.

$ _ 'for x in {1..3} ; do echo $x ; done'
    1
    2
    3

$ _ for x in \{1..3\} \; do echo \$x \; done
    1
    2
    3

The code for this function would only be this:

_(){ eval "$@" |& sed "s/^/\t/" ; return "$PIPESTATUS" ;}

As a side effect, this would merge STDERR into STDOUT in order to indent both, but on the other hand it also preserves the exit status of the given command.

You can append this line above to your ~/.bashrc file so that it will be available in all Bash sessions of your user.


The previous version of this answer suggested the function below, but that would not indent STDERR streams and also suppress return/exit codes in case the given command fails. Besides, it would have broken commands with quotes or significant whitespace due to the bad $* variable expansion instead of "$@", and probably there were even more problems...

_(){ sed "s/^/\t/" <($*); }