When I run this command:
echo "1" > /dev/tty # runs successfully
but when I run this:
echo "1" | /dev/tty #permission denied
What is the difference between these two operators > and | and why does the pipe cause an error?
Short answer: > must be followed by a filename or &n (n is a number), and | must be followed by another command invocation.
Details: In shell syntax, a call to some command contains several components. Example:
A=foo 2>/dev/null B=bar cmd arg1 arg2 >file 3>&4 arg3
Here, parameters 2>/dev/null, >file and 3>&4 are special parameters (containing an unescaped >¹), they are used to establish io-redirections, and can appear anywhere in the command line. Filedesciptor 2 is redirected to /dev/null, filedescriptor 1 (implicit) is redirected to file and filedescriptor 3 is redirected to what filedescriptor 4 was linked to.
Then, among remaining parameters, A=foo and B=bar contain =, so they are not considered as the command name: they give specific values to environment variables of the process to be launched.
Then comes the command cmd and the real arguments: arg1, arg2, arg3.
The pipe | is not part of a command invocation, it links two such invocations together. Example:
CC=gcc make 2>&1 | LESS=--quit-at-eof less
Output on filedescriptor 1 by the first process will be received as input on filedescriptor 0 by the second process, through a “pipe” which acts like a buffer.
—
1. In fact, the special characters like > are sometimes seen followed by a space. Even though this is allowed, the two (space-separated) strings must be understood as a single ‘entity’.
The | is used to pipe data between processes while > is used to redirect a stream to a file. /dev/tty is a "file"/device owned by root and its permissions are set to 666 as a result when you try to pipe to it your shell attempts to execute /dev/tty to stream data to it and it doesn't have execute permissions.