2

I want to write a C program, and I need to parse stdin. If I type cat file.txt | grep -v match, how does stdout from cat resolve with -v match? Are they concatenated? Are they two different strings? I ran cat /dev/pts/0 and file /dev/pts/0, so I didn't find anything (seemingly) useful there.

6

The standard definition for the main function of a C program is

int main(int argc, char *argv[])

Here, argc and argv are the command line arguments, -v and match for grep in this case. Note that they're not a single string, but the shell has already split the arguments to distinct strings (NUL/\0 terminated, as usual in C). argc contains the number of arguments, and argv the arguments themselves.

Standard input on the other hand is just a FILE *, you can use it directly with any of the stdio functions. fgets(buf, sizeof(buf), stdin) etc.


I'm not sure where you got cat /dev/pts/0. It would read from that particular pseudo-terminal, possibly conflicting with reads by your shell on that same terminal. (Try to open two terminals, xterm, SSH sessions, screen, whatever. Then run tty on the first one, it shows the name of the terminal there, e.g. /dev/pts/123. Run cat /dev/pts/123 (with the given name) in the second terminal, then try to type something in the first.)

| improve this answer | |
  • I assumed the tty was a text file for some reason, so I tried to read it. When that didn't work, I checked what kind of file it was. – Michael Christensen Jul 7 at 0:44
  • So stdin has the output of the piped command, and argc, argv have the options and stuff used with the command? Can stdin have the latter? – Michael Christensen Jul 7 at 0:58
  • @MichaelChristensen, I would use the phrase "stdin is connected to the pipe", but yes. You could run something like cat $(echo foobar), where the command substitution would take the output of echo and put it in the arguments of cat, so cat would see that foobar in argv. But that's a completely different construct from echo foobar | cat. – ilkkachu Jul 7 at 8:50
10

A pipe is a buffer allocated in the kernel with file descriptors associated with the read and write ends. When you run cat file.txt | grep -v match:

  • The shell creates a pipe (using the pipe() system call)
  • The shell fork()s. The child process uses the dup2() system call to close its standard output stream and to duplicate the write end of the pipe to standard output. (After this, writes to standard output will go to the kernel buffer.) Then the child exec()s cat with the updated standard output.
  • The shell fork()s again. The child uses the dup2() system call to close its standard input stream and to duplicate the read end of the pipe to standard input. (After this, reads from standard input will come from the kernel buffer.) Then the child exec()s grep with the updated standard input.

At this point, both cat and grep are running. If grep tries to read from standard input (the pipe) and the pipe is empty, the read will block. If cat tries to write to standard output (again, the pipe) and the pipe is full, the write will block. Otherwise, as cat writes to the buffer, grep can read from the buffer.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.