Write to stderr

23,143

Solution 1

It appears that the program is re-writting the various write() functions to detect whether you are printing to file descriptor 2 and then adding the relevant escape codes to make the output red at the terminal.

Unfortunately, in shell, when you do something like

echo "foo" 1>&2 

The function will still be calling write (or some other similar system call) on file descriptor 1. The output appears on fd 2 since file descriptor 1 has been dupped to file descriptor 2 by your shell.

Unfortunately, I don't know of way to write /directly/ to fd 2 in shell, but you can use awk. A function like this will write the arguments directly to file descriptor 2.

error() {
  awk " BEGIN { print \"$@\" > \"/dev/fd/2\" }"
}

I believe this is a feature of GNU awk that isn't part of POSIX but it also works on the awk provided on OS X.

Solution 2

That software hooks the write() system calls that apprear to write at file descriptor 2, that is known as stderr.

It is a shared library (so recompilation of the kernel is not necessary). As descripted in the installation manual it takes use of the environment varaible LD_PRELOAD. The dynamic linker can be influenced into modifying its behavior during the program's execution. These variables adjust the runtime linking process by searching for shared libraries at alternate locations.

The executable /bin/bash itself does not honour such variables, so bash itself uses the original pallette of system calls, not the modified ones. The redirection you mentioned in your question happend in bash. Not in the executable of echo. If echo could wirte to the error descriptor by itself (not via bash) the output would be red.

Python can write to stderr. See the proof (that should appear in red):

python -c 'import os; os.write(2, "error")'

Solution 3

Create a helper function:

echoerr() { printf "\033[0;31m%s\n\033[0m" "$*" >&2; }

And use it anywhere:

echoerr "something went wrong here"

This combines writing to stderr (>&2) and changing colors (solution taken from here https://stackoverflow.com/questions/5947742/how-to-change-the-output-color-of-echo-in-linux).

Share:
23,143

Related videos on Youtube

pfnuesel
Author by

pfnuesel

Updated on September 18, 2022

Comments

  • pfnuesel
    pfnuesel almost 2 years

    I'm using stderred to color all output streamed to stderr red. It's working fine. But when I write my own bash script and throw an error with echo 'error' 1>&2, it doesn't color the output in red. I reckon this is, because the command simply redirects the output to wherever the stderr file descriptor points to, but doesn't properly mark the message as belonging to stderr. Is that so? How can I properly write to stderr in bash?

    • Erik Kaplun
      Erik Kaplun over 8 years
      for the record, you can also do >&2 echo error according to this answer.
  • Rob C
    Rob C over 9 years
    Sounds like stderred is a nice idea implemented wrong. The approach I would have taken would be to create a new pts device and connect file descriptor 2 to that. Then a it could have a process read the data written to that file descriptor and rewrite it to the original pts with escape codes included. Then it wouldn't have needed to use LD_PRELOAD, and 1>&2 would have worked. (My approach probably wouldn't have been entirely without problems either, but I think it would have worked better.)
  • Kusalananda
    Kusalananda about 6 years
    You may want to test whether the standard error goes to a terminal before doing colour output.
  • VasyaNovikov
    VasyaNovikov about 6 years
    @Kusalananda TBH, I don't know how to do that, so I did not. Also, it's a function, so the real destination can change. Considering the question asked, not sure overall, could be just fine.
  • dotnetCarpenter
    dotnetCarpenter over 2 years
    @Kusalananda Does the following check look good to you? echoerr () { if [[ $(tty -s) -eq 0 ]]; then printf "\033[0;31m%s\n\033[0m" "$*" >&2; else printf "%s\n" "$*" >&2; fi }
  • VasyaNovikov
    VasyaNovikov over 2 years
    @dotnetCarpenter, if you want to test for tty, then you should rather write if tty -s; then ...... otherwise sounds good. Printing colors might be useful even outside of a tty context though, such as to a log file to be later viewed with less -R
  • Kusalananda
    Kusalananda over 2 years
    @dotnetCarpenter [ -t 2 ] && printf ... >&2 See man test.
  • dotnetCarpenter
    dotnetCarpenter over 2 years
    @VasyaNovikov good point about less -R and never seen an if statement without test, [] or [[]]. I didn't know that was allowed syntax :)
  • dotnetCarpenter
    dotnetCarpenter over 2 years
    @Kusalanada -t FD file descriptor FD is opened on a terminal. I get that 1= stdin, 2 = stdout and 3 = stderr but I have never seen that outside pipes - ala >&... Where is the documentation for that? Can I use 123 as a reference to those file descriptors anywhere outside arithmetic expansion?
  • Kusalananda
    Kusalananda about 2 years
    @dotnetCarpenter That's 0 for standard input and 1 and 2 for standard output and error. File descriptor 3 is the first descriptor available for other things (like duplicating one of the others or referring to a stream from or to a file etc.) You would use these numbers anywhere where the number that designates a file descriptor is expected. In the shell, that would mostly be in redirections, i.e., as in >&2, but also in the -t test.