4

It seems read does not write to standard output.

$ cat test.sh
#!/bin/bash
read -p "type a key and Enter" key
echo "the key was $key"
$ ./test.sh
type a key and Enterx
the key was x
$ ./test.sh | tee file
type a key and Enterx
the key was x
$ cat file
the key was x

Trying it without a script...

$ read -p "type a key and Enter" key | tee file
type a key and Enterx
$ cat file
$ 

The read command is described here. A brief description: "Read a line from standard input".

Information on the pipe, |, from The Linux Command Line (2nd Internet Edition) by William E. Shotts follows.

Using the pipe operator "|" (vertical bar), the standard output of one command can be piped to into the standard input of another: command1 | command2

From the man page for tee is this description:

read from standard input and write to standard output and files

The man page for tee is at this link.

Where is the list of all the other examples of programs that write to the console but actually do not use standard output, or in the absence of such a list, what is the general rule for knowing when a program that writes to the console is not using standard output?

It seems read violates the Principle of Least Astonishment.

wjandrea
  • 14,504
H2ONaCl
  • 10,039

2 Answers2

6

In your example, read is writing to stderr instead of stdout. Here's how I know:

$ read -p "Type a key and press Enter: " key >/dev/null
Type a key and press Enter: x
$ read -p "Type a key and press Enter: " key 2>/dev/null
x

You can do this test on any program whose output you want to redirect.

So the command you are looking for is this:

$ read -p "Type a key and press Enter: " key 2>&1 | tee file
Type a key and press Enter: x
$ cat file
Type a key and press Enter: $

For explanations of the above redirections:

wjandrea
  • 14,504
1

With what wjandrea said, that is correct that you can grab the stderr that read is doing. Unfortunately, trying to read in with the stderr does not keep the variable of key, so the output for echo $key will end up blank. However, in a script it will keep the variable because the read line itself is not being redirected from stderr to stdout 2>&1 in the script. Instead, script gets to keep the variable because it is now set before it gets to redirection. I think to make it easier, use echo lines instead. I have added all examples.

Example of your script:

:~$ cat test1.sh 
#!/bin/bash
read -p "type a key and Enter: " key
echo "the key was $key"

:~$ ./test1.sh | tee junk
type a key and Enter: G
the key was G

:~$ cat junk
the key was G

With 2>&1 redirection:

:~$ ./test1.sh 2>&1 | tee junk
type a key and Enter: G
the key was G

:~$ cat junk
type a key and Enter: the key was G

With echo line:

:~$ cat test.sh 
#!/bin/bash
echo -n "Type a key and press Enter: "
read key
echo "the key was $key"

echo line with tee command:

:~$ ./test.sh | tee junk
Type a key and press Enter: X
the key was X

:~$ cat junk
Type a key and press Enter: the key was X

Example of the no script:

With stderr:

:~$ read -p "Type a key and press Enter: " key 2>&1 |tee junk; echo "The key was $key" | tee -a junk
Type a key and press Enter: F
The key was 

:~$ cat junk
Type a key and press Enter: The key was 

With echo and multiple tee commands instead:

:~$ echo -n "Type a key and press Enter: " | tee junk; read key; echo "The key was $key" | tee -a junk
Type a key and press Enter: F
The key was F

:~$ cat junk
Type a key and press Enter: The key was F

Hope this helps!

Terrance
  • 43,712