Module 1 · Unit 2 · Lesson 2 of 5
Shell and Command Line
The primary interface through which you will interact with Linux for the rest of the course. Navigating the file system, running commands, managing files, and chaining programs together with pipes and redirection.
01 Introduction
Before graphical desktops, every interaction with a computer was textual. A user typed a command; the machine responded. That interface — the shell — is not a relic of an earlier era. It remains the most powerful and efficient way to interact with a UNIX-like system, and it is the primary interface you will use for every laboratory and programming assignment in this course.
The reason the shell endures is composability. Graphical applications are islands: to get data from one into another, you copy and paste, or you rely on a plugin that someone else wrote. Shell commands are small, focused tools that read from standard input and write to standard output, and the shell's redirection and pipeline mechanisms let you connect them in arbitrary ways. A pipeline of three commands can accomplish what would take a custom program in any other environment — often without writing a single line of code.
This lesson gives you the practical skills you need: moving around the file system, running and finding commands, managing files and directories, and combining tools with redirection, pipes, and simple scripts. The lessons that follow will build on this foundation to cover users, permissions, and the development environment.
02 Learning objectives
By the end of this lesson you will be able to
- Navigate the file system.
- Execute shell commands.
- Manage files and directories.
- Use redirection and pipes.
- Write simple shell scripts.
This lesson contributes to U2.2 and to course learning outcome CLO6.
03 Required reading
- Stevens & Rago — Advanced Programming in the UNIX Environment, 3rd ed., Sections 1.4–1.6 (files and directories, input and output, programs and processes). The classical presentation of how the shell interfaces with the kernel.
- Shotts, W. — The Linux Command Line, 5th ed., Chapters 1–6 (navigation, file operations, redirection, and shell basics). Freely available online.
-
Man pages:
man 1 bash,man 1 ls,man 1 cp,man 1 grep. The manual is the definitive reference for every command discussed in this lesson.
Reading strategy
Skim Shotts Chapters 1–6 for the practical material; read Stevens & Rago Sections 1.4–1.6 for the conceptual framework that ties the shell to the system-call interface from Lesson 2.1. Man pages are for reference; you do not need to read them cover to cover, but you should develop the habit of consulting them when a command does something unexpected.
04 Core content
4.1 What a shell is
A shell is a program that reads commands from
the user, interprets them, and executes them. It is a user-space
program — not part of the kernel — and it communicates with the
kernel through the system-call interface. When you type
ls, the shell:
- Reads the line from standard input.
- Parses it into a command name and arguments.
- Searches the
PATHfor an executable namedls. - Calls
forkto create a child process. - Calls
execvein the child to replace its image with thelsprogram. - Calls
waitto wait for the child to terminate. - Prints the next prompt.
This is the fork–exec–wait sequence from Lesson 2.1 in action.
Every command you type — from ls to gcc
to a script — runs through this mechanism.
4.2 Interactive vs. non-interactive shells
A shell can run in two modes:
- Interactive. A terminal is attached, the shell prints a prompt, and it reads commands from the user. This is what you get when you open a terminal or log in via SSH.
- Non-interactive. The shell reads commands from a file (a script) or from standard input and executes them without prompting. This is how shell scripts work — a text file containing commands that the shell executes in sequence.
The syntax is identical in both modes; the difference is only whether a prompt is displayed and a terminal is attached.
4.3 Command structure and the PATH
A shell command has a simple form:
command [option]... [argument]...
For example:
ls -l /home/alice
# │ │ └─ argument (path)
# │ └─── option (long listing)
# └───── command (list directory)
Options come in two forms:
-
Short options — single letter, prefixed with
a single dash:
-l,-a,-h. Multiple short options can be combined:ls -lahmeansls -l -a -h. -
Long options — a word, prefixed with two
dashes:
--all,--human-readable. Long options are usually more readable and easier to remember.
When you type a command, the shell searches for an executable file with that name in a list of directories called the PATH. You can see the current PATH:
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# The directories are separated by colons.
# The shell searches them left to right and runs the first match.
The which command tells you which file the shell
would run for a given command name:
$ which ls
/usr/bin/ls
$ which gcc
/usr/bin/gcc
$ which notacommand
(no output; the command was not found)
Why the PATH matters
If two programs have the same name in different directories on
the PATH, the one in the earlier directory wins. This is why
installing a program in /usr/local/bin can
override the system version in /usr/bin. It is
also why adding . (the current directory) to the
PATH is considered a security risk — it would let a malicious
file in the current directory shadow a system command.
4.4 File-system navigation
The file system is a tree, and every file has a unique path. There are two kinds of path:
-
Absolute — starts at the root, always begins
with
/. Example:/home/alice/notes.txt. -
Relative — interpreted from the current
working directory. Example:
notes.txtor../bob/README.
Two special directory names appear everywhere:
.— the current directory...— the parent directory.
/home/alice; docs/report.txt
(relative) and /home/alice/docs/report.txt
(absolute) refer to the same file.
Three commands are fundamental for navigation:
- pwd — print working directory
- Prints the absolute path of the current directory.
- cd — change directory
-
Changes the current working directory.
cd pathmoves topath;cdwith no argument moves to your home directory;cd -returns to the previous directory. - ls — list directory contents
-
Lists the files in a directory. Common options:
-l(long format),-a(include hidden files),-h(human-readable sizes),-t(sort by modification time),-R(recursive).
$ pwd
/home/alice
$ ls
docs notes.txt
$ ls -la
total 24
drwxr-xr-x 4 alice alice 4096 Oct 15 10:22 .
drwxr-xr-x 3 root root 4096 Oct 14 09:11 ..
-rw-r--r-- 1 alice alice 220 Oct 14 09:11 .bashrc
drwxr-xr-x 2 alice alice 4096 Oct 15 10:22 docs
-rw-r--r-- 1 alice alice 18 Oct 15 10:20 notes.txt
$ cd docs
$ pwd
/home/alice/docs
$ cd ..
$ pwd
/home/alice
4.5 File and directory management
The core file-management commands:
| Command | Purpose | Example |
|---|---|---|
touch |
Create an empty file, or update a file's timestamps | touch notes.txt |
mkdir |
Create a directory | mkdir docs, mkdir -p a/b/c |
cp |
Copy files or directories | cp a.txt b.txt, cp -r src/ dst/ |
mv |
Move or rename files or directories | mv old.txt new.txt |
rm |
Remove files or directories | rm file.txt, rm -r dir/ |
cat |
Print file contents to standard output | cat /etc/hostname |
less |
View a file one screen at a time | less /var/log/syslog |
head / tail |
Show the first or last lines of a file | tail -f /var/log/syslog |
find |
Search for files by name, size, or other attributes | find . -name "*.c" |
grep |
Search text for a pattern | grep "error" logfile.txt |
wc |
Count lines, words, and characters | wc -l file.txt |
man |
Read the manual page for a command | man ls |
rm is permanent
There is no recycle bin on the command line.
rm file.txt removes the file immediately. Worse,
rm -rf / (or any variation that reaches a wide
directory with -r and -f) will
recursively delete everything it can reach. Read commands
carefully before pressing Enter, especially when they contain
rm, wildcards, or a leading slash.
4.6 Getting help
There are several ways to find out what a command does and how to use it:
-
Man pages.
man lsshows the reference manual forls. The man page is divided into sections; section 1 is user commands, section 2 is system calls, section 3 is library functions, and so on. -
--help. Many commands support a--helpoption that prints a short usage summary. -
info. GNU commands often provide a longer, hyperlinked manual accessible with theinfocommand. -
apropos. Searches the short descriptions of all man pages for a keyword. Useful when you do not know the name of the command you need:apropos "copy file".
4.7 Redirection
Every process started by the shell has three standard streams:
- Standard input (stdin, fd 0)
- Where the process reads its input. By default, the terminal keyboard.
- Standard output (stdout, fd 1)
- Where the process writes normal output. By default, the terminal display.
- Standard error (stderr, fd 2)
- Where the process writes error messages. By default, also the terminal display — but a separate stream.
The shell can redirect these streams before starting a process:
-
> file— redirect stdout to a file, overwriting its contents. -
>> file— redirect stdout to a file, appending to it. -
< file— redirect stdin from a file. -
2> file— redirect stderr to a file. -
2>&1— redirect stderr to wherever stdout is currently going. Combined with>, this captures both streams in one file:cmd > out.txt 2>&1. -
> /dev/null— discard output by redirecting it to the special "null device" that throws away everything written to it.
# Save the listing of /etc to a file
$ ls /etc > etc-contents.txt
# Count the lines in that file
$ wc -l etc-contents.txt
142 etc-contents.txt
# Append another listing
$ ls /usr >> etc-contents.txt
$ wc -l etc-contents.txt
158 etc-contents.txt
# Save only the errors from a build
$ gcc broken.c 2> errors.txt
# Save both the output and the errors, interleaved
$ gcc -Wall broken.c > build.log 2>&1
4.8 Pipes
A pipe, written |, connects the
stdout of one command to the stdin of the next. This is the
mechanism that makes the shell truly powerful: rather than
writing a program to do everything, you chain small tools that
each do one thing well.
# Count how many files are in /etc
$ ls /etc | wc -l
142
# Find all lines in a log file that contain "error",
# then count how many there are
$ grep "error" /var/log/syslog | wc -l
37
# Sort the list of users on the system, remove duplicates, and page through it
$ cut -d: -f1 /etc/passwd | sort | uniq | less
# Show the ten largest files under /var in human-readable sizes
$ du -ah /var 2>/dev/null | sort -rh | head -10
Each command in a pipeline runs as a separate process, connected by a kernel-managed pipe (a buffer the kernel provides for interprocess communication). The commands run concurrently: as soon as the producer writes to the pipe, the consumer can begin reading, without waiting for the producer to finish. This streaming behaviour is what makes pipelines efficient even on large data.
The UNIX philosophy in a single pipe
"Write programs that do one thing and do it well. Write programs to work together." Pipes are the mechanism that makes this philosophy work. Every command in a pipeline is a small, focused tool; the shell combines them into something larger than any one would be alone.
4.9 Command substitution and variable expansion
The shell expands certain patterns before running a command:
-
Variable expansion.
$VARis replaced by the value of the variable.$PATH,$HOME,$USERare common examples. Use${VAR}when the variable name would otherwise be ambiguous. -
Command substitution.
$(command)runscommandand substitutes its output. For example,mkdir backup-$(date +%F)creates a directory namedbackup-2024-10-15. -
Arithmetic expansion.
$(( expression ))evaluates an arithmetic expression:echo $(( 3 + 4 ))prints7. -
Globbing.
*matches any sequence of characters,?matches any single character, and[abc]matches any character in the set. For example,rm *.tmpremoves every file ending in.tmp. Note that globbing happens in the shell, not in the command — the shell expands*.tmpinto the matching filenames before runningrm.
4.10 Shell scripts
A shell script is a text file containing a sequence of shell commands. To run it:
- Write the commands to a file.
- Make the file executable:
chmod +x script.sh. - Run it:
./script.shorbash script.sh.
A minimal script:
#!/bin/bash
# The first line is the "shebang": it tells the kernel
# which program should interpret this script.
echo "Hello from a shell script"
echo "Today is $(date +%F)"
echo "The current user is $USER"
The #!/bin/bash line is essential. When you run
./script.sh, the kernel reads the first two bytes;
if they are #!, it treats the rest of the line as
the path to the interpreter. The kernel then runs
/bin/bash with the script path as its argument.
Scripts can use control flow, variables, and conditionals:
#!/bin/bash
# Arguments
NAME="$1"
if [ -z "$NAME" ]; then
echo "Usage: $0 <name>" >&2
exit 1
fi
# Loops
for FILE in *.txt; do
if [ -f "$FILE" ]; then
LINES=$(wc -l < "$FILE")
echo "$FILE: $LINES lines"
fi
done
This script uses:
-
Positional parameters.
$1is the first argument,$0is the script name,$@is all arguments. -
Test expressions.
[ -z "$NAME" ]tests whetherNAMEis empty;[ -f "$FILE" ]tests whetherFILEexists and is a regular file. -
Exit codes. Every command returns an exit
code; 0 means success, non-zero means failure.
exit 1ends the script with code 1. -
Loops and conditionals.
for,if,whileare the standard control-flow constructs.
Shell scripts are covered in far more depth in the next lesson and in Lab 1. For now, the goal is to recognise the syntax and be able to read a simple script when you encounter one.
4.11 Scripts in this course
You will write shell scripts for at least three purposes in this course:
- Lab automation. Each laboratory has a set of commands to run and outputs to collect; wrapping them in a script makes the workflow reproducible.
- Test harnesses. When you implement a scheduler, a memory allocator, or a file-system simulator, you will want a script that runs a set of test cases and reports the results.
- Experiment automation. When you measure context-switch cost or page-fault rates, a script that runs the experiment across a range of parameters and collects the results in a consistent format saves an enormous amount of manual work.
The best way to learn is to type commands by hand. Every command you run at the prompt is a line you could put in a script later.
05 Worked example
To see the power of composition in action, let's build a small but realistic pipeline from scratch.
Task: find the ten most common words in a file
Suppose we have a text file and want to know which words appear most frequently. In a graphical environment, we might write a program. In the shell, we chain together a few small tools.
-
Get all words, one per line. The
trcommand translates characters; here we replace every non-letter with a newline.tr -cs '[:alpha:]' '\n' < input.txt -
Normalise case. Pipe through
tragain to convert to lowercase, so "The" and "the" are counted together.tr -cs '[:alpha:]' '\n' < input.txt | tr '[:upper:]' '[:lower:]' -
Sort the words. Now that all instances of
the same word are adjacent, we can count them.
tr -cs '[:alpha:]' '\n' < input.txt | tr '[:upper:]' '[:lower:]' | sort -
Count adjacent duplicates.
uniq -ccollapses runs of identical lines and prefixes each with a count.... | sort | uniq -c -
Sort by count.
sort -rnsorts numerically in reverse order, putting the highest counts first.... | uniq -c | sort -rn -
Take the top ten.
... | sort -rn | head -10
The full pipeline:
tr -cs '[:alpha:]' '\n' < input.txt \
| tr '[:upper:]' '[:lower:]' \
| sort \
| uniq -c \
| sort -rn \
| head -10
Sample output on a small corpus:
892 the
521 and
489 of
418 to
389 a
312 in
287 is
265 that
231 it
208 for
Six small commands, none of which knows anything about word frequency, combined to solve a problem that would otherwise require writing a custom program. This is the pattern that makes the shell so effective.
Turning it into a script. To reuse the pipeline, wrap it in a script:
#!/bin/bash
# topwords — print the N most common words in a file
# Usage: topwords FILE [N]
FILE="$1"
N="${2:-10}" # default to 10 if not given
if [ ! -f "$FILE" ]; then
echo "topwords: no such file: $FILE" >&2
exit 1
fi
tr -cs '[:alpha:]' '\n' < "$FILE" \
| tr '[:upper:]' '[:lower:]' \
| sort \
| uniq -c \
| sort -rn \
| head -n "$N"
Save this as topwords, run
chmod +x topwords, and use it as
./topwords input.txt 20. The script handles
missing arguments, validates its input, and behaves like any
other command on the system.
06 Interactive activity
Activity · work through the shell on your VM
Open a terminal and perform the following. Record what you observe for each step. The goal is to build muscle memory before the laboratories assume these skills.
-
Explore your home directory.
Run
pwd, thenls -la. What hidden files (starting with a dot) exist? The dotfiles configure your shell and other programs. -
Create a workspace.
Where are you now? Confirm withmkdir -p ~/comp3150/lab1 cd ~/comp3150/lab1 pwdpwd. -
Create files.
What are the permissions and sizes of the new files?touch file1.txt file2.txt file3.txt ls -l -
Write to a file.
What does the file contain after each command?echo "first line" > file1.txt echo "second line" >> file1.txt cat file1.txt -
Use a pipeline.
How many commands are inls /usr/bin | wc -l/usr/bin? Now count only the ones containing "sh":ls /usr/bin | grep sh | wc -l -
Redirect errors.
What did the error message say? Note thatcat /nonexistent 2> err.txt cat err.txt2>captured it while leaving stdout untouched. -
Use command substitution.
Note that the inner command runs first, and its output is substituted into the outer command's argument.echo "Today is $(date)" echo "Files here: $(ls | wc -l)" -
Write a small script.
Run it a few times, including after changing directory, to see the values change.cat > hello.sh << 'EOF' #!/bin/bash echo "Hello, $USER" echo "You are in $(pwd)" echo "There are $(ls | wc -l) files here" EOF chmod +x hello.sh ./hello.sh
Reflect: which of the commands you used made use of standard input, standard output, or standard error? Which relied on the shell expanding something (a variable, a command, a glob) before running the command itself?
07 Knowledge check
Check your understanding
Question 1
What is the difference between > and
>>?
Show answer
> redirects standard output to a file,
overwriting whatever the file contained.
>> also redirects standard output but
appends to the file instead of overwriting it.
The distinction is easy to forget and can cause
accidental data loss: cmd > log.txt
destroys the previous contents of log.txt.
Question 2
What is the difference between 2> and
2>&1?
Show answer
2> redirects standard error to a file,
leaving standard output going to the terminal.
2>&1 redirects standard error to
wherever standard output is currently going — so
combining them, as in cmd > out.txt 2>&1,
sends both streams to the same place. The order matters:
cmd 2>&1 > out.txt does something
different (it duplicates stderr to the current stdout
first, then redirects stdout — the stderr copy still goes
to the terminal).
Question 3
What does the PATH environment variable do,
and what happens when a command name is not in any of the
directories listed there?
Show answer
PATH is a colon-separated list of directories
the shell searches when looking for an executable file.
When you type a command name, the shell scans the
directories in order and runs the first matching
executable it finds. If no directory on the PATH contains
a matching executable, the shell reports
"command not found" and returns a non-zero exit status. To
run a program that is not on the PATH, you can give a
path explicitly: ./myprogram or
/opt/tools/myprogram.
Question 4
What is the purpose of the #!/bin/bash line at
the top of a shell script?
Show answer
./script.sh), the kernel reads the first two
bytes of the file. If they are #!, the rest
of the line is treated as the path to the interpreter, and
the kernel runs that interpreter with the script path as
its first argument. Without a shebang, the kernel does not
know how to execute the file directly; it must be invoked
through an explicit interpreter, such as
bash script.sh.
Question 5
Given a file data.txt, write a one-line command
that prints the number of lines containing the word
"warning".
Show answer
grep "warning" data.txt | wc -l
Or, using grep -c, which counts matching lines
directly:
grep -c "warning" data.txt
Both approaches count matching lines, but the second is
more efficient because it avoids the extra process and
the pipe. In general, when a single command can do the
job, prefer it over a pipeline.
08 Unit discussion
Discussion prompt
The UNIX shell was designed in an era when every interaction with a computer was textual. Today's environments are dominated by graphical interfaces and web-based tools, yet the shell remains the primary interface for system administration, software development, and cloud operations. Even web-based cloud consoles ultimately translate their clicks into API calls that map back to shell commands.
Why does the shell persist? Consider what properties of the command line make it resistant to replacement: composability, automation, scriptability, the low bandwidth required to transmit commands, and the fact that a shell session is inherently automatable. Are there contexts where the shell is genuinely inappropriate, or has it proven adaptable to every use case?
Post your response to the Unit 2 discussion forum and reply to at least two classmates. This activity supports CLO6 and CLO7.
09 Practice exercise
This ungraded exercise consolidates the lesson. Aim to spend about 45–60 minutes on it.
-
Build a directory tree by hand. Using only
mkdir,cd, andtouch, create the following structure inside your home directory:
Then runcomp3150/ ├── lab1/ │ ├── src/ │ └── tests/ ├── lab2/ │ └── docs/ └── notes.txtfind comp3150 -printto verify the structure. -
Use every redirection operator once.
For each of
>,>>,2>,2>&1, and<, write a small command that uses it and explain in one sentence what the operator did. -
Build a pipeline from memory. Without
consulting the lesson, write a pipeline that lists every
file in
/usr/bin, filters to only those that contain the letter "g", and prints the count. Then check your answer against the pattern shown in the lesson. -
Write a script that summarises a directory.
The script should take a directory path as its argument
and print:
- The number of files
- The number of subdirectories
- The total size in human-readable form
-
Automate a measurement. Write a script
that runs
ls -l /usr/bin | wc -lfive times, prints each result, and then prints the average. This is the shape of the measurement scripts you will write in later laboratories. -
Read a man page carefully. Run
man find. Find the option that searches by file size. Write a command that finds every file under/varthat is larger than 10 MB.
10 Summary
-
A shell is a user-space program that reads commands,
interprets them, and executes them by forking child processes
and calling
execve. -
The file system is a tree; paths are either absolute (starting
from
/) or relative (starting from the current working directory)..and..refer to the current and parent directories. -
Commands are found by searching the directories listed in the
PATHenvironment variable. -
The core file-management commands are
ls,cd,pwd,touch,mkdir,cp,mv, andrm. -
Standard input, standard output, and standard error are three
separate streams. Redirection (
>,>>,<,2>,2>&1) lets you control where each goes. -
Pipes (
|) connect the output of one command to the input of the next, allowing small tools to be composed into larger data-processing workflows. -
The shell expands variables (
$VAR), command substitutions ($(cmd)), arithmetic ($(( ... ))), and globs (*,?,[...]) before running a command. -
A shell script is a text file containing commands; the
#!/bin/bashline identifies the interpreter, and the script becomes executable withchmod +x.
Looking ahead
Lesson 2.3 turns to users and groups — how Linux identifies who is using the system and how it groups users for the purpose of access control. Understanding users and groups is a prerequisite for understanding permissions in Lesson 2.4.
11 References
- Stevens, W. R., & Rago, S. A. Advanced Programming in the UNIX Environment, 3rd ed., Sections 1.4–1.6. Addison-Wesley, 2013.
-
Shotts, W. The Linux Command Line, 5th ed., Chapters
1–6. No Starch Press, 2019. Freely available at
linuxcommand.org. - Newham, C., & Rosenblatt, B. Learning the bash Shell, 3rd ed. O'Reilly, 2005.
- Robbins, A., & Beebe, N. H. F. Classic Shell Scripting. O'Reilly, 2005.
-
Linux man pages:
man 1 bash,man 1 ls,man 1 cp,man 1 grep,man 1 find,man 7 glob.