In today’s section, we'll investigate the behavior of a shell to kick off the process control unit and problem set 5.
College students are required to attend section live. TFs will record your attendance. For more on the attendance policy and what to do if you miss section refer to the syllabus here and here.
Extension students are welcome to attend section live (in-person or zoom) or watch the recording (Canvas > DCE Class Recordings). Both methods count towards your participation grade. If you attend a live section, TFs will record your attendance. If you watch the recording, fill out this reflection form.
Building intuition
The pset in this unit introduces a bunch of process control system calls through the medium of a shell implementation. A shell is a program responsible for running other programs; it’s the kind of program behind the command line terminal. You've been using a shell since you first started programming, probably mostly to compile and run your programs. But there are so many useful (and fun) things that you can accomplish using a command line that strings one or more shell commands together.
Common operators used to build command lines are:
- command list seperators 
;(to run preceding command the foreground) and&(to run preceding command in the background) - conditional operators (
cmd1 && cmd2) and (cmd1 || cmd2). Each of these operators runs two commands, but the second command is run conditionally, based on the status of the first command.- with 
&&,cmd2runs ONLY if thecmd1exits with status zero. - with 
||,cmd2runs ONLY if thecmd1(1) DOES NOT exit, or (2) exits with status nonzero. 
 - with 
 - the pipe operator 
cmd1 | cmd2runs two commands, connecting the standard output ofcmd1to the standard input ofcmd2. These commands run in parallel. - redirection operators, where some of a command’s file descriptors are sent to disk files.
< filename: The command’s standard input is taken fromfilename> filename: The command’s standard output is sent tofilename2> filename: The command’s standard error is sent tofilename
 
Here are some commonly-installed, commonly-used programs that you can call
directly from the shell. Documentation
for these programs can be accessed via the man page, e.g. man cat, or
often also through a help switch, e.g. cat --help.
| Shell Program | Description | 
|---|---|
cat | 
Write named files (or standard input) to standard output. | 
wc | 
Count lines, words, and characters in named files (or standard input). | 
head -n N | 
Print first N lines of standard input. | 
head -c N | 
Print first N characters of standard input. | 
tail -n N | 
Print last N lines of standard input. | 
echo ARG1 ARG2... | 
Print arguments to standard output. | 
printf FORMAT ARG... | 
Print arguments with printf-style formatting. | 
true | 
Silently succeed (exit with status 0). | 
false | 
Silently fail (exit with status 1). | 
yes | 
Print y (or any arguments) forever. | 
sort | 
Sort lines in input. | 
uniq | 
Drop duplicate lines in input (or print only duplicate lines). | 
tr | 
Change characters; e.g., tr a-z A-Z makes all letters uppercase. | 
ps | 
List processes. | 
curl URL | 
Download URL and write result to standard output. | 
sleep N | 
Pause for N seconds, then exit with status 0. | 
cut | 
Cut selected portions of each line of a file. | 
grep PATTERN | 
Print lines in named files (or standard input) that match a regular expression PATTERN. | 
tac | 
Write lines in named files (or standard input) in reverse order to standard output. | 
exit [STATUS] | 
Exit the shell with status STATUS (default 0). | 
sh -c "COMMANDLINE" | 
Run another shell executing "COMMANDLINE". | 
Build some intuition for shell commands and operators with the following exercises. There is often more than one correct answer!
EXERCISE. Write a command line that compiles program
P(usingmake) and runs it only if the compilation succeeded.
EXERCISE. Augment your last answer to redirect standard output and standard error to seperate files.
EXERCISE. Write a command line that lists all
.ccfiles in the pset4 directory.
EXERCISE. Write a command line that finds all
.ccfiles in the pset4 directory that contain the stringio61_seek. Assume the shell is in the pset4 directory (meaningpwdwould return/home/cs61-user/cs61-psets/pset4).
EXERCISE. Write a command line to download the contents of this webpage and then display the first ten lines in the terminal.
EXERCISE. Write a command line that tells you how many commits Eddie Kohler has made to a git repostory.
EXERCISE. Write a command line that tells you how many lines have been added to a git repository since the last commit.
EXERCISE. Write a command line that prints 'not ready for grading' if a student has not written their name in their AUTHORS.md, but otherwise doesn't print anything else. Hint: the handout AUTHORS.md file uses the placeholder
(Your name.).
Command line breakdown
Now we'll formalize how complex command lines are built.
- A command line consists of
- Zero or more conditionals, each of which comprises
- One or more pipelines, each of which comprises
- One or more commands.
 
 
 - One or more pipelines, each of which comprises
 
 - Zero or more conditionals, each of which comprises
 
A command is a basic request to execute a program with some arguments.
echo foo, for example, is a command. Pipelines, conditionals, and command
lines combine commands to build more complex behaviors.
A precise way to explain command lines is with a BNF grammar. Here’s the shell grammar:
command_line ::= (empty) | conditional | conditional ";" command_line | conditional "&" command_line conditional ::= pipeline | conditional "&&" pipeline | conditional "||" pipeline pipeline ::= command | pipeline "|" command command ::= word | redirection | command word | command redirection redirection ::= redirectionop filename redirectionop ::= "<" | ">" | "2>"
The grammar says, for instance, that a command_line is zero or more
conditionals, separated (and optionally terminated) by ; or &. It also
defines conditionals in terms of pipelines, and pipelines in terms of
commands.
EXERCISE. Test your understanding of the command line grammar. What are the conditionals in the following command line?
echo foo & echo bar | grep b && echo hello, there ; echo done < /dev/null(It might be helpful to underline them.)
EXERCISE. What are the pipelines in that command line?
EXERCISE. What are the commands in that command line?
EXERCISE. What are the redirections in that command line, if any?
EXERCISE. Can any pipeline span across more than one conditional? Why or why not?
EXERCISE. Talk through the structure of the parser in phase 2 of the pset, and how it processes the command line from these exercises.
Command line scientists
In order to fully implement your shell you will need to completely understand the behavior of each shell operator. It’s possible to learn a lot by constructing “experiments”, namely command lines, and observing their behavior on a real shell!
For example, the behaviors of the && and || conditional operators can be
explored with different combinations of programs like false, true, and
echo.
# Hypothesis: `A && B` runs `B` iff `A` exits with status 0.
$ true && echo X
X
$ false && echo X
$ sh -c "exit 2" && echo X
# Hypothesis not falsified!
# Hypothesis: `A || B` runs `B` iff `A` does not exit with status 0.
$ true || echo X
$ false || echo X
X
$ sh -c "exit 2" || echo X
X
# Hypothesis not falsified!
# Hypothesis: The `sleep` command exits with status 1.
$ sleep 10 && echo Done
[10 seconds go by, then:] Done
# Hypothesis falsified 😢: it looks like `sleep` exits with status 0.
Indeed, it is true that A && B executes B only when A exits with status
0, and A || B executes B only when A does not exit with status 0!
In these exercises, you’ll attempt to explore more complex shell properties.
EXERCISE. Design command lines that test whether commands that are part of a single conditional are grouped left to right. That is, try and determine whether, given the chain
A || B && C, commands are left associative:
A || Bruns first.
- So
 Aruns first.- Then, depending on
 A’s status,Bruns or is skipped.- Then, depending on
 A || B’s status,Cruns or is skipped.Or right associative:
Aruns first.- Then, depending on
 A’s status,B && Cruns or is skipped.Or something entirely different.
EXERCISE. Design command lines that test whether two-process pipelines, such as
A | B, executeAandBconcurrently (at the same time) or serially (Bdoes not start untilAhas completed).
EXERCISE. Design command lines that test whether the exit status of a conditional equals the exit status of the last-executed command in that conditional.
Hint. The
$?shell variable equals the exit status of the most-recently-executed foreground conditional. For instance:$ true $ echo $? 0 $ false $ echo $? 1 $ sh -c "exit 2" $ echo $? 2
EXERCISE. Design command lines that test whether the exit status of a pipeline equals the exit status of its rightmost command. (Try to avoid using
$?.)