Unix streams - jaredgorski.org

Unix streams

unix, streams, data, input, output, io, programs

Unix streams were invented to act like garden hoses, piping data between programs on a computer.

In Unix, there are three “standard” streams:

  • stdin - standard input, or the input data for a program
  • stdout - standard output, or the output data from a program
  • stderr - standard error, or any error-related output data from a program

Everything is a file in Unix, meaning that Unix is simply composed of files communicating with each other via streams. Consider the TTY, which uses a file to represent each TTY instance and handle its input and output:

  • tty command prints the filepath to the file that represents the current TTY instance:
$ tty
/dev/ttys001

This file receives stdin from any input device drivers via the terminal runtime and pipes that input data through stdout to programs and/or files on the machine, which may or may not use the TTY’s stdin stream to send output back up through the TTY to the terminal instance.

An interesting experiment is invoking the cat command without any stdin:

$ cat
Everything I write before pressing Enter
Everything I write before pressing Enter
Gets logged right after
Gets logged right after

Interestingly, the same thing happens when cat is sent the filepath to the tty file as stdin:

$ cat $(tty)
Everything I write before pressing Enter
Everything I write before pressing Enter
Gets logged right after
Gets logged right after

This happens because cat simply reads the contents of a file at a given filepath and writes its stdout to the stdin stream of the TTY instance, unless cat is specifically sent somewhere else. Essentially, a pipe (|) changes the destination of the preceding program’s stdout. So, all programs write their stdout to the /dev/tty file by default, unless piped somewhere else instead.

Piping tty to cat simply prints the stdout of the tty command:

$ tty | cat
/dev/ttys001

Redirection

Input/output data can be redirected as well using the input/output redirection operators. Redirection operators allow for reading from and writing to files.

  • > - output redirection (write to, will overwrite entire file)
    $ cat file1.txt > file2.txt
    
  • >> - output redirection (append to)
    $ cat file1more.txt >> file2.txt
    
  • < - input redirection (read from stdin) (note the output redirection at the beginning)
    $ > file2.txt < file1more.txt
    
  • << - here document (AKA, heredoc) (delimiter can be anything, not just ‘EOF’)
    $ > file2.txt << EOF
    this is
    a stream
    of input
    terminated by the custom delimiter
    EOF
    $ cat file2.txt
    this is
    a stream
    of input
    terminated by the custom delimiter
    

Since there are two standard output streams (stdout and stderr), output can be redirected selectively by preceding output redirection with a file descriptor for the desired standard output stream. The file descriptor for stdout is 1, so the command cat file1.txt 1> file2.txt will only redirect the stdout output stream. This is the same as > without a file descriptor; 1 is the default. To redirect only the stderr stream, use 2. To redirect both stdout and stderr, use &. Like stdout, stderr redirects back to the TTY directly by default.

Redirecting between TTY instances

Combining these redirection concepts with the fact that the TTY is just a file allows for redirecting output to other TTY instances, provided you know the proper TTY file to redirect to:

TERMINAL 1
$ tty
/dev/ttys001
$ echo "Hello terminal 2!" > /dev/ttys002
TERMINAL 2
$ tty
/dev/ttys002
$ Hello terminal 2!

Further reading