2

I learn that pipe (|) is used to pass stdout into subshell's stdin.

But, command less must have filename argument like less file1.txt

However, when I use command like ls -l /root | less, it works.

So, I assumed that in this case, less takes stdin file which is written from ls -l /root's stdout. I mean, in real, less stdin when less do its own command. But, because of another command, I got confused. It's tr command.

tr command doesn't take any file argument like tr a-z A-Z file1.txt. It just take stdin from keyboard or redirected stdin. But, command ls -l /root | tr a-z A-Z is possible. Then, what I assumed is wrong.

How pipe works in real? The basic is that pipe passes main shell's standard output into subshell's standard input. But, I can't know main shell's standard output goes to subshell's standard input file or just it takes situation that I enter the characters from keyboard. But, when I see above examples, shell takes both situations.

A.Cho
  • 469
  • less will accept a filename, but if no file is given, it reads from stdin. That is specific to the less command so not relevant to tr. Pipes in general are implemented as a special type of file called "FIFO" (first in first out) which is temporarily created by the shell to allow one command to read what another command outputs. In a simple two command pipeline, the stdout of the first command is directed to the FIFO (write-only), and the stdin of the second command is directed from the FIFO (read only). But you can pretend the first command writes directly to the second. – Wildcard Feb 21 '16 at 08:29
  • But, when I use less without file argument(for example, just less), it doesn't take stdin from keyboard. Is it just internal mechanism from less? – A.Cho Feb 21 '16 at 08:37
  • See my updated reply. – jlliagre Feb 21 '16 at 09:05
  • Yes, less(1) takes commands from the keyboard, taking input from there simultaneously makes no sense. Other programs that don't take commands just don't care to check. – vonbrand Feb 21 '16 at 16:26

2 Answers2

4

I learn that pipe (|) is used to pass stdout into subshell's stdin.

It passes the left command stdout to the right command stdin. Whether one or both of these commands run in a subshell is shell implementation specific.

In any case, the shell doesn't care about arguments being passed or not to either commands. It is up to the programs to do what they want with their stdin and stdout, including ignoring them.

Note too that programs are able to detect if their stdin is a tty, i.e. interactive keyboard, or not and act accordingly. This is what you observe with the less command which, when given no arguments, normally reads its standard input but refuses to process it if it is a tty, as its source code shows :

  if (isatty(fd0))
  {
    error("Missing filename (\"less --help\" for help)", NULL_PARG);
    quit(QUIT_OK);
  }
jlliagre
  • 61,204
2

So, I assumed that in this case, less takes stdin file which is written from ls -l /root's stdout.

This is correct, and it doesn't contradict what you observed with tr.

The shell's pipeline construct (PRODUCER | CONSUMER) creates an anonymous pipe before starting the two processes PRODUCER and CONSUMER. An anonymous pipe is a type of file that doesn't have a name, it doesn't have a directory entry, but it can be read and written normally. In a pipeline, the shell connects the write end of the pipe to the producer's stdout and the read end of the pipe to the consumer's stdin.

The tr command only ever reads data from stdin and writes to stdout. The less command does this only if you don't pass it a file name on the command line; if you pass a file name to less, it reads from this file instead of reading from stdin. What less does is a common convention, followed by many similar applications that read data from one file.

You may also be interested in what is meant by connecting STDOUT and STDIN? and How can a command have more than one output?