No, this is not possible.
Your attempt doesn't work for a fundamental reason: stderr is an attribute of each process, not some system-wide thing. Standard error (stderr) just means file descriptor 2 of the process. read … </dev/stderr
is the same thing as read <&2
: it reads from whatever file is open on file descriptor 2 of the shell process. If you run this in a terminal, it reads from the terminal.
I strongly recommend reading what is meant by connecting STDOUT and STDIN?.
What you're trying to do isn't actually “read from stderr”, it's read what some-random-program
writes to stderr, i.e. read what the program writes to file descriptor 2. You can only do that if the program is writing to a pipe and you're reading to the other end. Or you could set up some different kind of file: a socket would also work (but is harder to set up), or you could have the program write to a regular file and read from that file (but with no direct way to know when to stop reading: if you reach the end of the file, the program might still write more), or you could have the program write to a terminal for which you're a terminal emulator, or you could have the program write to a character device and be a kernel driver for that device. All of these methods have in common that the program is writing to something, and you read from the “other end” of that thing.
All of these methods have in common that _the caller of some-random-program
needs to set something up (or some-random-program
itself, but here it isn't collaborating). First someone has to set up the communication channel (and if not the caller, nobody will), then the caller of some-random-program
has to connect the write end of the channel to file descriptor 2 of some-random-program
, and the caller needs to hand you the read end of the channel. This is what the pipe (|
) operator does in the shell, except it connects the write end to file descriptor 1 (stdout), not file descriptor 2 (stderr).
In the construct some-random-program | myscript.sh
, the two sides some-random-program
and myscript.sh
run in parallel. You have no control over the order in which the two sides do thing. Depending on how fast the programs are, some-random-program
might write to stderr before myscript.sh
runs the first instruction in the script. So even if there was a way to cause some-random-program
's stderr to change, it would be too late.
(Technically, there is a way myscript.sh
could spy on some-random-program
: have it work like a debugger and either snoop on what the program writes, or have it inject a system call into the program's process to open something different on file descriptor 2. Injecting a system call may or may not confuse the program, depending on how much it cares. On many systems, you'd have to disable security restrictions to allow a process to debug another process that isn't its child, e.g. sysctl kernel.yama.ptrace_scope
on Linux.)
So, if you want your script to see both stdout and stderr from some-random-program
, you need to set up the file descriptors of some-random-program
accordingly:
some-random-program 2>&1 | myscript.sh
Bash, ksh and zsh let you abbreviate this to some-random-program |& myscript.sh
.
If you want to handle the program's stdout and stderr separately, see How to grep standard error stream (stderr)?. Note that you lose synchronization.