{"captions":[{"content":"TOMMY: In this video, we'll learn about","startTime":7060,"duration":1360,"startOfParagraph":false},{"content":"redirecting and pipes.","startTime":8420,"duration":1720,"startOfParagraph":false},{"content":"So far, we've been using functions like printf to","startTime":10140,"duration":2640,"startOfParagraph":false},{"content":"output data to the terminal and functions like GetString","startTime":12780,"duration":2810,"startOfParagraph":false},{"content":"to allow the user to provide input to our","startTime":15590,"duration":1930,"startOfParagraph":false},{"content":"program using the keyboard.","startTime":17520,"duration":1970,"startOfParagraph":false},{"content":"Let's quickly take a look at a program that gets a line of","startTime":19490,"duration":2390,"startOfParagraph":false},{"content":"input from the user and then outputs it.","startTime":21880,"duration":4080,"startOfParagraph":false},{"content":"On line 7, we're prompting the user for a string, and","startTime":25960,"duration":3030,"startOfParagraph":true},{"content":"then on line 8, we're printing it back out.","startTime":28990,"duration":2690,"startOfParagraph":false},{"content":"Let's compile and run our program.","startTime":31680,"duration":3540,"startOfParagraph":false},{"content":"Great.","startTime":35220,"duration":680,"startOfParagraph":false},{"content":"The string we provided was echoed back","startTime":35900,"duration":1720,"startOfParagraph":false},{"content":"to us at the terminal.","startTime":37620,"duration":1550,"startOfParagraph":false},{"content":"This happened because the printf function wrote to a","startTime":39170,"duration":2940,"startOfParagraph":false},{"content":"stream called standard out, or s-t-d-out.","startTime":42110,"duration":4110,"startOfParagraph":false},{"content":"When something is written to stdout, it's by default","startTime":46220,"duration":3010,"startOfParagraph":false},{"content":"displayed by the terminal.","startTime":49230,"duration":1880,"startOfParagraph":false},{"content":"So that's all well and good, but what if, instead of simply","startTime":51110,"duration":2610,"startOfParagraph":true},{"content":"displaying the string, we wanted to save it to a file?","startTime":53720,"duration":3980,"startOfParagraph":false},{"content":"For example, we might want to remember exactly what our","startTime":57700,"duration":2770,"startOfParagraph":false},{"content":"program did when we gave it a particular input later.","startTime":60470,"duration":3980,"startOfParagraph":false},{"content":"One approach would be to do this in our C program, using","startTime":64450,"duration":2820,"startOfParagraph":false},{"content":"some special functions for writing to files that we'll","startTime":67270,"duration":2410,"startOfParagraph":false},{"content":"see in another video.","startTime":69680,"duration":1590,"startOfParagraph":false},{"content":"Even easier, though, would be to somehow","startTime":71270,"duration":1990,"startOfParagraph":false},{"content":"redirect stdout to a file.","startTime":73260,"duration":2830,"startOfParagraph":false},{"content":"That way, when printf writes to stdout, the contents will","startTime":76090,"duration":3690,"startOfParagraph":false},{"content":"be written to a file rather than","startTime":79780,"duration":1940,"startOfParagraph":false},{"content":"displayed by the terminal.","startTime":81720,"duration":1690,"startOfParagraph":false},{"content":"We can do just that by adding a greater-than sign, followed","startTime":83410,"duration":3280,"startOfParagraph":false},{"content":"by a file name, to the command we use to execute our program.","startTime":86690,"duration":4130,"startOfParagraph":false},{"content":"So, rather than simply executing ./redirect, we can","startTime":90820,"duration":3910,"startOfParagraph":true},{"content":"run ./redirect, followed by a greater than sign, followed by","startTime":94730,"duration":4150,"startOfParagraph":false},{"content":"filename, like file.txt.","startTime":98880,"duration":2650,"startOfParagraph":false},{"content":"Let's see what happens.","startTime":101530,"duration":2760,"startOfParagraph":false},{"content":"OK.","startTime":104290,"duration":840,"startOfParagraph":false},{"content":"Notice that this time, nothing was displayed at the terminal,","startTime":105130,"duration":3340,"startOfParagraph":false},{"content":"but we haven't modified the contents of our","startTime":108470,"duration":1820,"startOfParagraph":false},{"content":"C program at all.","startTime":110290,"duration":1750,"startOfParagraph":false},{"content":"Let's now examine the contents of this directory with ls.","startTime":112040,"duration":4050,"startOfParagraph":false},{"content":"All right.","startTime":116090,"duration":540,"startOfParagraph":true},{"content":"We now have a new file in our directory called file.txt,","startTime":116630,"duration":4210,"startOfParagraph":false},{"content":"which is the file name we supplied when we ran our","startTime":120840,"duration":2800,"startOfParagraph":false},{"content":"Redirect program.","startTime":123640,"duration":1410,"startOfParagraph":false},{"content":"Let's open up file.txt.","startTime":125050,"duration":2970,"startOfParagraph":false},{"content":"And here, we can see that the stdout out of redirect was","startTime":128020,"duration":3820,"startOfParagraph":false},{"content":"written to the file called file.txt.","startTime":131840,"duration":3710,"startOfParagraph":false},{"content":"So let's run the previous command again, but supplying a","startTime":135550,"duration":2920,"startOfParagraph":false},{"content":"different input this time.","startTime":138470,"duration":1605,"startOfParagraph":false},{"content":"Okay.","startTime":145140,"duration":760,"startOfParagraph":false},{"content":"Let's take a look at file.txt now.","startTime":145900,"duration":2305,"startOfParagraph":false},{"content":"We can see here that the file has been overwritten, so our","startTime":151070,"duration":3510,"startOfParagraph":true},{"content":"original input isn't there anymore.","startTime":154580,"duration":2540,"startOfParagraph":false},{"content":"If we instead want to append to this file, putting the new","startTime":157120,"duration":3160,"startOfParagraph":false},{"content":"input below the existing contents of the file, we can","startTime":160280,"duration":3320,"startOfParagraph":false},{"content":"use two greater-than signs instead of just one.","startTime":163600,"duration":3200,"startOfParagraph":false},{"content":"Let's try that.","startTime":166800,"duration":1250,"startOfParagraph":false},{"content":"Now, if we open file.txt again, we can see both of our","startTime":172160,"duration":5750,"startOfParagraph":false},{"content":"input lines.","startTime":177910,"duration":1670,"startOfParagraph":false},{"content":"In some cases, we might want to discard any","startTime":179580,"duration":2600,"startOfParagraph":false},{"content":"output of our program.","startTime":182180,"duration":1670,"startOfParagraph":false},{"content":"Rather than writing the output to a file and then deleting","startTime":183850,"duration":2600,"startOfParagraph":false},{"content":"the file when we're done with it, we can write a to special","startTime":186450,"duration":2860,"startOfParagraph":false},{"content":"file called /dev/null.","startTime":189310,"duration":3050,"startOfParagraph":false},{"content":"When anything is written to /dev/null--","startTime":192360,"duration":2800,"startOfParagraph":false},{"content":"or just devnull for short--","startTime":195160,"duration":1800,"startOfParagraph":false},{"content":"it is automatically discarded.","startTime":196960,"duration":1990,"startOfParagraph":false},{"content":"So think of devnull as a black hole for your data.","startTime":198950,"duration":4340,"startOfParagraph":false},{"content":"So now we've seen how the greater than sign can redirect","startTime":203290,"duration":2780,"startOfParagraph":true},{"content":"stdout, let's see how we can redirect standard in--","startTime":206070,"duration":3540,"startOfParagraph":false},{"content":"or s-t-d-in--","startTime":209610,"duration":1640,"startOfParagraph":false},{"content":"the analogue of stdout.","startTime":211250,"duration":2300,"startOfParagraph":false},{"content":"While functions like printf write to the stream called","startTime":213550,"duration":2460,"startOfParagraph":false},{"content":"stdout, GetString and similar functions read from the stream","startTime":216010,"duration":4490,"startOfParagraph":false},{"content":"called stdin, which, by default, is the stream of","startTime":220500,"duration":3270,"startOfParagraph":false},{"content":"characters typed at the keyboard.","startTime":223770,"duration":2520,"startOfParagraph":false},{"content":"We can redirect stdin using the less than sign, followed","startTime":226290,"duration":3720,"startOfParagraph":false},{"content":"by a filename.","startTime":230010,"duration":1360,"startOfParagraph":false},{"content":"Now, rather than prompting the user for input at the","startTime":231370,"duration":2630,"startOfParagraph":false},{"content":"terminal, a program will open the file we specified and use","startTime":234000,"duration":3870,"startOfParagraph":false},{"content":"its lines as input.","startTime":237870,"duration":1920,"startOfParagraph":false},{"content":"Let's see what happens.","startTime":239790,"duration":2830,"startOfParagraph":true},{"content":"Great.","startTime":242620,"duration":660,"startOfParagraph":false},{"content":"The first line of file.txt has been printed to the terminal","startTime":243280,"duration":4310,"startOfParagraph":false},{"content":"because we're calling GetString once.","startTime":247590,"duration":2570,"startOfParagraph":false},{"content":"If we had another call to GetString in our program, the","startTime":250160,"duration":3010,"startOfParagraph":false},{"content":"next line of file.txt would have been used as","startTime":253170,"duration":2979,"startOfParagraph":false},{"content":"input to that call.","startTime":256149,"duration":1841,"startOfParagraph":false},{"content":"Again, we haven't modified our C program at all.","startTime":257990,"duration":3060,"startOfParagraph":false},{"content":"We're only changing how we run it.","startTime":261050,"duration":2570,"startOfParagraph":false},{"content":"And also remember, we haven't redirected stdout this time,","startTime":263620,"duration":3460,"startOfParagraph":false},{"content":"so the output of the program was still","startTime":267080,"duration":1890,"startOfParagraph":false},{"content":"displayed at the terminal.","startTime":268970,"duration":2070,"startOfParagraph":false},{"content":"We can, of course, redirect both stdin","startTime":271040,"duration":2460,"startOfParagraph":false},{"content":"and stdout like this.","startTime":273500,"duration":3820,"startOfParagraph":false},{"content":"Now, file2.txt contains the first line of file.txt.","startTime":277320,"duration":6230,"startOfParagraph":false},{"content":"So, using these operators, we've been able to read and","startTime":283550,"duration":2590,"startOfParagraph":true},{"content":"write from text files.","startTime":286140,"duration":1990,"startOfParagraph":false},{"content":"Now, let's see how we can use the output of one program as","startTime":288130,"duration":3760,"startOfParagraph":false},{"content":"the input to another program.","startTime":291890,"duration":2820,"startOfParagraph":false},{"content":"So here's another simple C program I","startTime":294710,"duration":1940,"startOfParagraph":false},{"content":"have here called hello.c.","startTime":296650,"duration":3540,"startOfParagraph":false},{"content":"As you can see, this simply outputs \"Hi","startTime":300190,"duration":2427,"startOfParagraph":false},{"content":"there!\" to the user.","startTime":302617,"duration":1813,"startOfParagraph":false},{"content":"If I want redirect to use as input the output of hello--","startTime":304430,"duration":4460,"startOfParagraph":false},{"content":"another program--","startTime":308890,"duration":1300,"startOfParagraph":false},{"content":"I could first redirect the stdout of hello to a file called","startTime":310190,"duration":3730,"startOfParagraph":false},{"content":"input.txt, then redirect the stdin of redirect to that same","startTime":313920,"duration":5040,"startOfParagraph":false},{"content":"file--input.txt.","startTime":318960,"duration":2230,"startOfParagraph":false},{"content":"So I can do ./hello > input.txt.","startTime":321190,"duration":5540,"startOfParagraph":false},{"content":"Press Enter to execute this.","startTime":326730,"duration":2080,"startOfParagraph":false},{"content":"Followed by ./redirect <","startTime":328810,"duration":3100,"startOfParagraph":false},{"content":"input.txt, and execute that.","startTime":331910,"duration":3360,"startOfParagraph":false},{"content":"So we can shorten this a bit with a semicolon, which allows","startTime":335270,"duration":3020,"startOfParagraph":false},{"content":"us to run two or more commands on the same line.","startTime":338290,"duration":3070,"startOfParagraph":false},{"content":"So I can say, ./hello > input.txt, semicolon,","startTime":341360,"duration":6560,"startOfParagraph":false},{"content":"./redirect < input.txt.","startTime":347920,"duration":2660,"startOfParagraph":false},{"content":"So this works, but it still feels pretty inelegant.","startTime":353850,"duration":2890,"startOfParagraph":true},{"content":"I mean, do we really need this intermediary text file that's","startTime":356740,"duration":2790,"startOfParagraph":false},{"content":"no longer necessary after redirect runs?","startTime":359530,"duration":2990,"startOfParagraph":false},{"content":"Luckily, we can avoid this extra text file using what's","startTime":362520,"duration":3260,"startOfParagraph":false},{"content":"called a pipe.","startTime":365780,"duration":1440,"startOfParagraph":false},{"content":"If I say, ./hello | ./redirect, then the stdout of","startTime":367220,"duration":6520,"startOfParagraph":false},{"content":"the program on the left--","startTime":373740,"duration":1570,"startOfParagraph":false},{"content":"in this case, hello--","startTime":375310,"duration":1430,"startOfParagraph":false},{"content":"will be used as the standard input for the","startTime":376740,"duration":2230,"startOfParagraph":false},{"content":"program on the right.","startTime":378970,"duration":1400,"startOfParagraph":false},{"content":"In this case, redirect. So let's run this.","startTime":380370,"duration":4480,"startOfParagraph":false},{"content":"There we go.","startTime":384850,"duration":1080,"startOfParagraph":true},{"content":"We can see that the output of hello was used as the input","startTime":385930,"duration":4150,"startOfParagraph":false},{"content":"for redirect.","startTime":390080,"duration":1440,"startOfParagraph":false},{"content":"By stringing commands together using pipes, we form what's","startTime":391520,"duration":3370,"startOfParagraph":false},{"content":"called a pipeline, since our output is essentially moving","startTime":394890,"duration":3230,"startOfParagraph":false},{"content":"through a sequence of commands.","startTime":398120,"duration":2470,"startOfParagraph":false},{"content":"Using pipes, we can do some cool stuff without needing to","startTime":400590,"duration":2980,"startOfParagraph":false},{"content":"write any code at all.","startTime":403570,"duration":2300,"startOfParagraph":false},{"content":"For example, let's say we want to know how many files are","startTime":405870,"duration":2890,"startOfParagraph":false},{"content":"inside of this directory.","startTime":408760,"duration":1870,"startOfParagraph":false},{"content":"Using a pipe, we can combine the ls command with the wc--","startTime":410630,"duration":4570,"startOfParagraph":false},{"content":"or wordcount--","startTime":415200,"duration":1260,"startOfParagraph":false},{"content":"command.","startTime":416460,"duration":1390,"startOfParagraph":false},{"content":"Ls will output each file in the directory to stdout, and","startTime":417850,"duration":4380,"startOfParagraph":false},{"content":"wc will tell us how many lines were given to it via stdin.","startTime":422230,"duration":5810,"startOfParagraph":false},{"content":"So, if we say ls | wc -l--","startTime":428040,"duration":4400,"startOfParagraph":false},{"content":"supplying the -l flag to wc to tell it to count lines--","startTime":432440,"duration":4360,"startOfParagraph":false},{"content":"we can see exactly how many files are","startTime":436800,"duration":2460,"startOfParagraph":false},{"content":"in the current directory.","startTime":439260,"duration":2680,"startOfParagraph":false},{"content":"So let's take a look at one more example.","startTime":441940,"duration":2630,"startOfParagraph":true},{"content":"I have here a file called students.txt,","startTime":444570,"duration":3170,"startOfParagraph":false},{"content":"with a list of names.","startTime":447740,"duration":1860,"startOfParagraph":false},{"content":"However, these names aren't in any order it all, and it looks","startTime":449600,"duration":3130,"startOfParagraph":false},{"content":"like a few names are repeated.","startTime":452730,"duration":2120,"startOfParagraph":false},{"content":"What we want is a list of unique names in alphabetical","startTime":454850,"duration":3660,"startOfParagraph":false},{"content":"order, saved to a file called final.txt.","startTime":458510,"duration":4040,"startOfParagraph":false},{"content":"We could, of course, write a C program to do this for us.","startTime":462550,"duration":2660,"startOfParagraph":false},{"content":"But it's going to get unnecessarily","startTime":465210,"duration":1350,"startOfParagraph":false},{"content":"complex pretty quickly.","startTime":466560,"duration":2000,"startOfParagraph":false},{"content":"Let's instead use pipes and some built-in-tools to solve","startTime":468560,"duration":3180,"startOfParagraph":false},{"content":"this problem.","startTime":471740,"duration":1560,"startOfParagraph":false},{"content":"The first thing we need to do is read the file students.txt.","startTime":473300,"duration":4460,"startOfParagraph":true},{"content":"The cat command will do just that.","startTime":477760,"duration":2770,"startOfParagraph":false},{"content":"It will read in the specified file and write","startTime":480530,"duration":2700,"startOfParagraph":false},{"content":"its contents to stdout.","startTime":483230,"duration":2520,"startOfParagraph":false},{"content":"After we've read the text file, we'll","startTime":485750,"duration":1820,"startOfParagraph":false},{"content":"want to sort the names.","startTime":487570,"duration":1920,"startOfParagraph":false},{"content":"The sort command can handle this for us.","startTime":489490,"duration":3020,"startOfParagraph":false},{"content":"Sort will output the line supplied via stdin to stdout","startTime":492510,"duration":4320,"startOfParagraph":false},{"content":"in sorted order.","startTime":496830,"duration":2480,"startOfParagraph":false},{"content":"In order to supply the contents of students.txt to","startTime":499310,"duration":4140,"startOfParagraph":false},{"content":"sort's stdin, we could use a pipe to combine cat and sort.","startTime":503450,"duration":6150,"startOfParagraph":false},{"content":"So I can execute cat students.txt | sort and","startTime":509600,"duration":4840,"startOfParagraph":false},{"content":"press Enter.","startTime":514440,"duration":1200,"startOfParagraph":false},{"content":"And now, we see the contents of students.txt in","startTime":515640,"duration":3669,"startOfParagraph":false},{"content":"alphabetical order.","startTime":519309,"duration":1600,"startOfParagraph":false},{"content":"So let's add another command--","startTime":520909,"duration":1951,"startOfParagraph":true},{"content":"uniq, or unique--","startTime":522860,"duration":1870,"startOfParagraph":false},{"content":"to our pipeline.","startTime":524730,"duration":1500,"startOfParagraph":false},{"content":"As you might guess, uniq, when supplied a sorted sequence of","startTime":526230,"duration":3580,"startOfParagraph":false},{"content":"lines via stdin, will output the unique lines.","startTime":529810,"duration":3840,"startOfParagraph":false},{"content":"So now we have cat students.txt","startTime":533650,"duration":3260,"startOfParagraph":false},{"content":"| sort | uniq.","startTime":536910,"duration":3130,"startOfParagraph":false},{"content":"Finally, we can save the output of the pipeline to a","startTime":540040,"duration":3290,"startOfParagraph":false},{"content":"file via cat students.txt | sort | uniq","startTime":543330,"duration":5760,"startOfParagraph":false},{"content":"> final.txt.","startTime":549090,"duration":3350,"startOfParagraph":false},{"content":"So, if we open up final.txt, we have exactly what we were","startTime":552440,"duration":3820,"startOfParagraph":false},{"content":"looking for:","startTime":556260,"duration":1010,"startOfParagraph":false},{"content":"a list of unique names in alphabetical order,","startTime":557270,"duration":2910,"startOfParagraph":false},{"content":"saved to a text file.","startTime":560180,"duration":1970,"startOfParagraph":false},{"content":"By the way, we also could have said sort <","startTime":562150,"duration":3870,"startOfParagraph":false},{"content":"students.txt | uniq > final.txt to do exactly","startTime":566020,"duration":6270,"startOfParagraph":false},{"content":"the same thing, using each of the operators we've seen in","startTime":572290,"duration":3110,"startOfParagraph":false},{"content":"this video.","startTime":575400,"duration":1180,"startOfParagraph":false},{"content":"My name is Tommy, and this is CS50.","startTime":576580,"duration":2960,"startOfParagraph":true}]}