Normally, tr
shouldn't be able to write that error message because it should have been killed by a SIGPIPE signal when trying to write something after the other end of the pipe has been closed upon termination of head
.
You get that error message because somehow, the process running tr
has been configured to ignore SIGPIPEs. I suspect that might be done by the popen()
implementation in your language there.
You can reproduce it by doing:
sh -c 'trap "" PIPE; tr -dc "[:alpha:]" < /dev/urandom | head -c 8'
You can confirm that's what is happening by doing:
strace -fe signal sh your-program
(or the equivalent on your system if not using Linux). You'll then see something like:
rt_sigaction(SIGPIPE, {SIG_IGN, ~[RTMIN RT_1], SA_RESTORER, 0x37cfc324f0}, NULL, 8) = 0
or
signal(SIGPIPE, SIG_IGN)
done in one process before that same process or one of its descendants executes the /bin/sh
that interprets that command line and starts tr
and head
.
If you do a strace -fe write
, you'll see something like:
write(1, "AJiYTlFFjjVIzkhCAhccuZddwcydwIIw"..., 4096) = -1 EPIPE (Broken pipe)
The write
system call fails with an EPIPE error instead of triggering a SIGPIPE.
In any case tr
will exit. When ignoring SIGPIPE, because of that error (but that also triggers an error message). When not, it exits upon receiving the SIGPIPE. You do want it to exit, since you don't want it carrying on reading /dev/urandom
after those 8 bytes have been read
by head
.
To avoid that error message, you can restore the default handler for SIGPIPE with:
trap - PIPE
Prior to calling tr
:
popen("trap - PIPE; { tr ... | head -c 8; } 2>&1", ...)
As others have said, this is because the stdin
of sh
has been redirected to read from the pipe, it is not connected to the terminal as it would normally be. One thing you can do to get around this is to use /dev/tty
to force the script to read from the terminal. Eg:
#!/bin/sh
read -p "Are you sure [Y/n]?" line </dev/tty
case "$line" in
y|Y) echo "confirmed"
;;
*) echo "not confirmed"
;;
esac
Normally you would only do this if you specifically want to prevent people from scripting the input, eg:
echo Y | sh confirmation.sh
This would still read from the terminal even though the user might expect this to automatically input Y
at the prompt. It is common for programs that expect a password to do this.
Best Answer
Simply put, because the program is not written to do so. It is up to the programmers to decide if their software can read from STDIN or if it requires an input file. In the case of
readlink
, itsman
page states (emphasis mine):As a general rule, programs that take input from STDIN are designed to somehow parse that input. When you pipe data to
readlink
it receives a text stream and has no idea what to do with it since it only deals with files and not their contents. The same is true for programs likels
orcd
orcp
etc. Only programs that deal with text/data streams can accept input from a pipe.