TOMMY: In this video, we'll learn about redirecting and pipes. So far, we've been using functions like printf to output data to the terminal and functions like GetString to allow the user to provide input to our program using the keyboard. Let's quickly take a look at a program that gets a line of input from the user and then outputs it. On line 7, we're prompting the user for a string, and then on line 8, we're printing it back out. Let's compile and run our program. Great. The string we provided was echoed back to us at the terminal. This happened because the printf function wrote to a stream called standard out, or s-t-d-out. When something is written to stdout, it's by default displayed by the terminal. So that's all well and good, but what if, instead of simply displaying the string, we wanted to save it to a file? For example, we might want to remember exactly what our program did when we gave it a particular input later. One approach would be to do this in our C program, using some special functions for writing to files that we'll see in another video. Even easier, though, would be to somehow redirect stdout to a file. That way, when printf writes to stdout, the contents will be written to a file rather than displayed by the terminal. We can do just that by adding a greater-than sign, followed by a file name, to the command we use to execute our program. So, rather than simply executing ./redirect, we can run ./redirect, followed by a greater than sign, followed by filename, like file.txt. Let's see what happens. OK. Notice that this time, nothing was displayed at the terminal, but we haven't modified the contents of our C program at all. Let's now examine the contents of this directory with ls. All right. We now have a new file in our directory called file.txt, which is the file name we supplied when we ran our Redirect program. Let's open up file.txt. And here, we can see that the stdout out of redirect was written to the file called file.txt. So let's run the previous command again, but supplying a different input this time. Okay. Let's take a look at file.txt now. We can see here that the file has been overwritten, so our original input isn't there anymore. If we instead want to append to this file, putting the new input below the existing contents of the file, we can use two greater-than signs instead of just one. Let's try that. Now, if we open file.txt again, we can see both of our input lines. In some cases, we might want to discard any output of our program. Rather than writing the output to a file and then deleting the file when we're done with it, we can write a to special file called /dev/null. When anything is written to /dev/null-- or just devnull for short-- it is automatically discarded. So think of devnull as a black hole for your data. So now we've seen how the greater than sign can redirect stdout, let's see how we can redirect standard in-- or s-t-d-in-- the analogue of stdout. While functions like printf write to the stream called stdout, GetString and similar functions read from the stream called stdin, which, by default, is the stream of characters typed at the keyboard. We can redirect stdin using the less than sign, followed by a filename. Now, rather than prompting the user for input at the terminal, a program will open the file we specified and use its lines as input. Let's see what happens. Great. The first line of file.txt has been printed to the terminal because we're calling GetString once. If we had another call to GetString in our program, the next line of file.txt would have been used as input to that call. Again, we haven't modified our C program at all. We're only changing how we run it. And also remember, we haven't redirected stdout this time, so the output of the program was still displayed at the terminal. We can, of course, redirect both stdin and stdout like this. Now, file2.txt contains the first line of file.txt. So, using these operators, we've been able to read and write from text files. Now, let's see how we can use the output of one program as the input to another program. So here's another simple C program I have here called hello.c. As you can see, this simply outputs "Hi there!" to the user. If I want redirect to use as input the output of hello-- another program-- I could first redirect the stdout of hello to a file called input.txt, then redirect the stdin of redirect to that same file--input.txt. So I can do ./hello > input.txt. Press Enter to execute this. Followed by ./redirect < input.txt, and execute that. So we can shorten this a bit with a semicolon, which allows us to run two or more commands on the same line. So I can say, ./hello > input.txt, semicolon, ./redirect < input.txt. So this works, but it still feels pretty inelegant. I mean, do we really need this intermediary text file that's no longer necessary after redirect runs? Luckily, we can avoid this extra text file using what's called a pipe. If I say, ./hello | ./redirect, then the stdout of the program on the left-- in this case, hello-- will be used as the standard input for the program on the right. In this case, redirect. So let's run this. There we go. We can see that the output of hello was used as the input for redirect. By stringing commands together using pipes, we form what's called a pipeline, since our output is essentially moving through a sequence of commands. Using pipes, we can do some cool stuff without needing to write any code at all. For example, let's say we want to know how many files are inside of this directory. Using a pipe, we can combine the ls command with the wc-- or wordcount-- command. Ls will output each file in the directory to stdout, and wc will tell us how many lines were given to it via stdin. So, if we say ls | wc -l-- supplying the -l flag to wc to tell it to count lines-- we can see exactly how many files are in the current directory. So let's take a look at one more example. I have here a file called students.txt, with a list of names. However, these names aren't in any order it all, and it looks like a few names are repeated. What we want is a list of unique names in alphabetical order, saved to a file called final.txt. We could, of course, write a C program to do this for us. But it's going to get unnecessarily complex pretty quickly. Let's instead use pipes and some built-in-tools to solve this problem. The first thing we need to do is read the file students.txt. The cat command will do just that. It will read in the specified file and write its contents to stdout. After we've read the text file, we'll want to sort the names. The sort command can handle this for us. Sort will output the line supplied via stdin to stdout in sorted order. In order to supply the contents of students.txt to sort's stdin, we could use a pipe to combine cat and sort. So I can execute cat students.txt | sort and press Enter. And now, we see the contents of students.txt in alphabetical order. So let's add another command-- uniq, or unique-- to our pipeline. As you might guess, uniq, when supplied a sorted sequence of lines via stdin, will output the unique lines. So now we have cat students.txt | sort | uniq. Finally, we can save the output of the pipeline to a file via cat students.txt | sort | uniq > final.txt. So, if we open up final.txt, we have exactly what we were looking for: a list of unique names in alphabetical order, saved to a text file. By the way, we also could have said sort < students.txt | uniq > final.txt to do exactly the same thing, using each of the operators we've seen in this video. My name is Tommy, and this is CS50.