To add to the other answer: the pipe operator tells the shell that the two commands should be organized in a pipeline, as in the flow of text from one to the other. For that, the shell creates an anonymous pipe, i.e. a FIFO file-like channel, by calling the kernel. Then the shell runs the two commands, passing the input of the pipe to the first command as its stdout file descriptor, and the output of the pipe to the second command as its stdin. So text goes from stdout of the first command to stdin of the second one via the pipe.
If the pipe symbol denoted a separate command, that program would need to get hold of the processes of the other two commands somehow, then pass file descriptors for the anonymous pipe to them (assuming this is possible between processes that aren't parent and child), and those programs would need to swap their stdout and stdin with these descriptors, when they're already running—under the danger of potential loss of output in the meantime. This all is rather easier accomplished by the shell, which already knows the two processes, has special parent relationship with them, and can supply the file descriptors right at the start.
|
. Try.&
being an ordinary command would make parsing tricky and somewhat arbitrary, which suggests it's maybe not the approach that designers would choose[
is a command, would you say it is not, because we can't find it in*/bin/
? ;)