CSC 161 | Grinnell College | Spring, 2009 |
Imperative Problem Solving and Data Structures | ||
This lab continues the discussion of Linux from the introductory Linux lab and also provides examples of how C programs can be used within the Linux environment.
One powerful type of I/O redirection within Linux is called a "pipe" (represented by the vertical bar "|", which on many keyboards is located on the same key as the backslash). A pipe allows you to connect utilities in a "pipeline." A pipe causes the data sent to stdout from one utility to be re-directed into stdin of another utility. We say that the output from the first utility is "piped" to the input of the next utility.
Use to following command that allows you to page through a long directory listing.
ls -l /bin | less
The fact that many Linux utilities can accept their input from one file, multiple files, or stdin makes them very versatile. Pipes take this versatility one step farther: any command or utility that can accept input from stdin can also accept input from a pipe. Any command or utility that sends output to stdout can also send output through a pipe.
To combine more than one program, we can string multiple pipes together to create longer pipelines, like so:
command | command | command
Many Linux utilities that accept input from stdin and send output to stdout are known as "filters" because, in one way or another, they filter their input to produce output. These utilities are especially apt for creating useful pipelines. In the first laboratory on Basic Linux Commands, you have worked with several filters, including less, tail, and cat.
The following table lists some additional filters. All of these filters can accept their input from regular files, stdin, or a pipe. None of them modify their original input; rather, they generate new output that reflects a modified version of the input.
Utility | Description | Example usage |
wc | "word count" - counts characters, words, and lines in input | wc -l ~/.bashrc |
sort | sorts lines in input | sort -k2 ~coahranm/share/csc201/sciencefac.txt |
uniq | "unique" - removes (or reports) duplicate lines in input | uniq ~coahranm/share/csc201/duplicates.txt |
grep | searches for a target string in input | grep li ~coahranm/share/csc201/duplicates.txt |
cut | removes parts of lines from input | cut -d' ' -f2 ~coahranm/share/csc201/sciencefac.txt |
diff | reports the differences between two files | diff ~walker/public_html/courses/153.sp09/labs/lab-linux-c.shtml ~walker/public_html/courses/153.sp09/labs/lab-linux-c.shtml~ |
Use the filters given above (and other utilities if needed) to perform the following tasks. Note that for some of the tasks you may need to combine filters with pipes.
Count the lines of source code in a program you wrote earlier this semester for this course.
Determine the number of user accounts on the MathLAN. Recall that each account has a directory in /home.
Print a list (in the terminal window, not on a printer) of faculty in Grinnell College's Science Division, sorted by last name. The file ~coahranm/share/csc201/sciencefac.txt contains the data you need.
Print a list of faculty in the Biology Department. Your list should not include faculty in any other department.
Consider one of the programs you wrote earlier this semester. Take a quick look at it, using less to remind yourself of a variable name that is used in several places in the file. Now use grep to print a listing of the lines that include that variable. Get grep to print the line number (in the source file) for each line of output as well.
Note that it can be very useful to use grep in this way when you return to a project after taking a long break from it. For example, you might want to find every instance of a given class -- in any source file in the project -- as part of re-acquainting yourself with your code.
Print a list of all Grinnell faculty named David.
Hint: To do this, it would be helpful to create a single list that combines all the entries in the three faculty lists I have provided. But instead of generating a separate combined file, you can do this on the fly using cat as shown below. This is where cat gets its name -- from its ability to concatenate multiple files.
cat ~coahranm/share/csc201/socialfac.txt ~coahranm/share/csc201/humanfac.txt ~coahranm/share/csc201/sciencefac.txt
Print a unique list of departments in the Humanities Division.
The names provided in ~coahranm/share/csc201/ give the faculty for the various departments, and the Chair of each department is denoted by an asterisk. Use grep to output a list of Department Chairs in one (or all) of the divisions. It might also be nice to sort your list by last name.
In this final section of the lab, we briefly describe a few useful capabilities. In each case, these options can be worthwhile as you work within the Linux environment, but in the interests of time we provide few experiments here.
You are probably already familiar with the idea of "wildcards" in filenames. For example, you can use the command "ls *.ss" to get a listing of all the files with the extension .ss.
What allows this to work? The shell parses your input, discovers the asterisk in it, and "expands" the command to include all files that match the given pattern. This ability to expand commands based on special characters in the input is also called globbing.
Further, the asterisk is not the only special character used for globbing. Here are some more.
Special Character | Is replaced by... | Example(s) |
* | matches any string (including zero characters) | cat ~coahranm/share/csc201/*fac.txt | less |
? | matches any single character | ls -ld /usr/bin/gc? ls /usr/lib/lib?.a |
[...] | matches any single character inside the brackets | ls /usr/lib/lib[xX]*.a |
On occasion, we want to keep the shell from treating special characters specially.
There is a file with the following goofy name in my share directory:
~coahranm/share/csc201/goofy file name
What do you expect will happen if we try to list its contents using the following command? Give it a try to be sure.
cat ~coahranm/share/csc201/goofy file name
You may have an idea how to work around this problem. If so, try it to make sure it works.
In fact, there are two ways to deal with it.
You can quote the file name, as follows. The single quotation marks keep the shell from treating characters inside them specially. In this case, it keeps the shell from parsing the line into four separate tokens.
cat 'goofy file name'
you can escape individual characters with a backslash. Again this keeps the shell from interpreting these characters in their usual (specialized) way. Be sure to try this one as well.
cat goofy\ file\ name
Command substitution allows you to embed one command inside another, using "backquotes" to delimit the nested command. (You should be able to find the backquote character in the upper-left of the keyboard, with the tilde.)
When you do this, the shell first executes the backquoted command, then substitutes the result that the command output to stdout in place of the command itself. Finally, the shell interprets and runs the resulting command string.
Try these, looking up any of the commands you are not familiar with already.
echo There are `ls | wc -l` files in my current working directory. echo Today is `date +%A`. It is now `date +%r`.
When we begin writing shell scripts later in the semester, you will find this ability useful for creating informative output messages.
This document is available on the World Wide Web as
http://www.walker.cs.grinnell.edu/courses/153.sp09/labs/lab-linux-c.html
created January 2007 by Marge Coahran revised January 2008 by Marge Coahran revised 10 April 2008 by Henry M. Walker last revised 3 April 2009 by Henry M. Walker |
![]() ![]() |
For more information, please contact Henry M. Walker at walker@cs.grinnell.edu. |