How to distinguish standard error from regular output

Use bash redirection and process substitution to programmatically distinguish standard error from regular output.

The idea

The idea is to prepend each line of output with custom pattern using process substitution.

$ du -hs /var/log 2> >(awk '{print "[STDERR] " $0}') 1> >(awk '{print "[STDOUT] " $0}')
[STDERR] du: cannot read directory '/var/log/couchdb': Permission denied
[STDERR] du: cannot read directory '/var/log/redis': Permission denied
[STDERR] du: cannot read directory '/var/log/gdm3': Permission denied
[STDERR] du: cannot read directory '/var/log/speech-dispatcher': Permission denied
[STDERR] du: cannot read directory '/var/log/samba/cores': Permission denied
[STDOUT] 2.6G   /var/log

This way you can use custom format according to your needs.

$ find /etc -name fstab  2> >(awk '{print "[\033[1;31mSTDERR\033[0m] " $0}') 1> >(awk '{print "[\033[1;34mSTDOUT\033[0m] " $0}')
[STDERR] find: '/etc/ssl/private': Permission denied
[STDERR] find: '/etc/polkit-1/localauthority': Permission denied
[STDERR] find: '/etc/libvirt/secrets': Permission denied
[STDERR] find: '/etc/ipsec.d/private': Permission denied
[STDERR] find: '/etc/lvm/backup': Permission denied
[STDERR] find: '/etc/lvm/archive': Permission denied
[STDERR] find: '/etc/cups/ssl': Permission denied
[STDERR] find: '/etc/vpnc': Permission denied
[STDOUT] /etc/fstab

Usage scenario #1

export desired redirections to the environment and use eval builtin command to read and concatenate it together into a single command.

$ export distinguish_output="2> >(awk '{print \"[\033[1;31mSTDERR\033[0m] \" \$0}') 1> >(awk '{print \"[\033[1;34mSTDOUT\033[0m] \" \$0}')"
$ eval df -h / $distinguish_output
[STDOUT] Filesystem                  Type  Size  Used Avail Use% Mounted on
[STDOUT] /dev/mapper/ubuntu--vg-root ext4  232G  161G   59G  74% /

You can define this variable inside ~/.bashrc file to use it later.

Usage scenario #2

You can use exec builtin command to alter existing redirections.

$ (exec 2> >(awk '{print "[\033[1;31mSTDERR\033[0m] " $0}') 1> >(awk '{print "[\033[1;34mSTDOUT\033[0m] " $0}'); touch  /etc/sudoers.d/local)
[STDERR] touch: cannot touch '/etc/sudoers.d/local': Permission denied

Remember to execute command in a sub-shell. Trust me, you do not want to mess with you current shell redirections.

Usage scenario #3

For simple use cases you can define shell function, it all depends on your needs.

$ function distinguish_out {
  (
    exec 2> >(awk '{print "[\033[1;31mSTDERR\033[0m] " $0}') 1> >(awk '{print "[\033[1;34mSTDOUT\033[0m] " $0}');
    eval $*;
  )
}
$ distinguish_out find /var/log -name syslog
[STDERR] find: '/var/log/couchdb': Permission denied
[STDERR] find: '/var/log/redis': Permission denied
[STDERR] find: '/var/log/gdm3': Permission denied
[STDERR] find: '/var/log/speech-dispatcher': Permission denied
[STDERR] find: '/var/log/samba/cores': Permission denied
[STDOUT] /var/log/installer/syslog
[STDOUT] /var/log/syslog

You can create an alias and store it alongside the preceding function inside ~/.bashrc file.

Additional notes

I cannot guarantee the order in which the standard output and error are printed to the screen.