Missing Semester Lecture 1: Introduction to the Shell
What is Shell
- Terminal runs shell.
- The Shell takes the commands you type, translates them into instructions the kernel understands, and then displays the results back to you.
- Bash stands for “Bourne Again Shell” — it’s a specific software implementation of a Shell, used mainly in command-line environments.
- Origin of the name: Its predecessor was
sh(the Bourne Shell), written by Steven Bourne. Later, the GNU Project enhanced and rewrote it, jokingly calling it “Bourne Again” — hence Bash. - Status: It’s the default Shell on most Linux distributions and on macOS (before Catalina), and it’s the most commonly used command-line tool for servers and developers.
- Origin of the name: Its predecessor was
- Before macOS Catalina, Bash was the default Shell on Mac. Starting with macOS Catalina (10.15), Apple switched the default login Shell to zsh.
- zsh (Z Shell) is a Shell that’s largely Bash-compatible but adds many features. It was created by Paul Falstad in 1990 at Princeton.
Diving into Shell
1 | caiguu@JACKERZHANG-MB0 ~ % date |
“caiguu” means the user, and the “JACKERZHANG-MB0” means the computer name. “~” means current directory. “%” or “$” means now I’m not the administrator. “date” is the program I just run, and it prints the date.
Shell also takes arguments.
1 | caiguu@JACKERZHANG-MB0 ~ % echo hello world |
Now take a look at argument parsing. It will take the whole string, and pares it by space. The first word is the program name, and all the things behind are arguments. In this example, “echo” is the program name, and “hello”, “world” are two arguments. This echo program takes “hello” and “world”, and prints them out.
1 | caiguu@JACKERZHANG-MB0 ~ % echo hello world |
Important commands
man
Provides helping documents.
Also can be used by --help or -h.
cd
cd is one of the most basic and most used commands in any Shell. It changes your current working directory — the folder you’re “standing in.”
An absolute path starts from the root of the filesystem and gives the full address of a file or folder.
- Always starts with
/(on macOS and Linux). - Works no matter where you currently are.
- Is unambiguous — there’s only one file at that exact address.
A relative path is interpreted from your current working directory. It does not start with /.
- Depends on where you are right now.
- Shorter and more convenient for everyday use.
- Common special symbols:
.= current directory..= parent directory~= home directory (technically a Shell shortcut, not a path character)
Tab completion is a feature that lets you press the Tab key to have the Shell automatically finish (or suggest) what you’re typing.
Instead of typing a long file name or command by hand, you type the first few characters and hit Tab — the Shell fills in the rest.
$Path
$PATH is an environment variable that tells the Shell where to look for executable programs when you type a command.
1 | caiguu@JACKERZHANG-MB0 ~ % echo $PATH |
It will walk through these paths one by one, until the target program is found.
Also use which to search for the target program in $PATH.
1 | caiguu@JACKERZHANG-MB0 ~ % which date |
ls
ls stands for “list”. It lists the contents of a directory — files and subdirectories.
| Flag | Meaning | Example |
|---|---|---|
-l |
Long format — permissions, owner, size, date | ls -l |
-a |
All — include hidden files (starting with .) |
ls -a |
-h |
Human-readable sizes (KB, MB, GB) | ls -lh |
-t |
Sort by time, newest first | ls -lt |
-r |
Reverse order | ls -lr |
-R |
Recursive — list subdirectories too | ls -R |
-S |
Sort by size, largest first | ls -lS |
-1 |
One entry per line | ls -1 |
-d |
List the directory itself, not its contents | ls -ld /tmp |
-i |
Show inode numbers | ls -li |
-G |
Colorized output (macOS) | ls -G |
--color |
Colorized output (Linux) | ls --color=auto |
cat
cat stands for “concatenate”. Its primary job is to join files together and print their contents to the terminal.
1 | cat file.txt # print file contents |
| Flag | Meaning | Example |
|---|---|---|
-n |
Number all lines | cat -n file.txt |
-b |
Number non-blank lines only | cat -b file.txt |
-s |
Squeeze multiple blank lines into one | cat -s file.txt |
-E |
Show $ at the end of each line |
cat -E file.txt |
-T |
Show tabs as ^I |
cat -T file.txt |
-A |
Show all non-printing characters (-vET) |
cat -A file.txt |
-v |
Show non-printing characters | cat -v file.txt |
head and tail
head— shows the beginning of a file (by default, the first 10 lines).tail— shows the end of a file (by default, the last 10 lines).
They’re the counterpart to cat, which prints the whole file. For large files (logs, datasets, configs), head and tail let you peek at the contents without flooding your terminal.
1 | head file.txt # first 10 lines |
Also can change the lines of head and tail:
1 | head -n 20 file.txt # first 20 lines |
1 | tail -n 20 file.txt # last 20 lines |
grep
grep stands for “Global Regular Expression Print”. It searches through text — files, command output, or streams — and prints lines that match a pattern.
1 | $ grep "error" app.log |
The basic syntax is:
1 | grep [options] pattern [file...] |
These are some common forms:
1 | grep "pattern" file.txt # search a file |
| Flag | Meaning | Example |
|---|---|---|
-i |
Case-insensitive | grep -i "error" app.log |
-r |
Recursive — search directories | grep -r "TODO" src/ |
-n |
Show line numbers | grep -n "error" app.log |
-v |
Invert — show non-matching lines | grep -v "debug" app.log |
-c |
Count matches | grep -c "error" app.log |
-l |
Show only filenames with matches | grep -l "error" *.log |
-L |
Show only filenames without matches | grep -L "error" *.log |
-w |
Match whole words only | grep -w "cat" file.txt |
-x |
Match whole lines only | grep -x "hello" file.txt |
-A N |
Show N lines after match | grep -A 3 "error" app.log |
-B N |
Show N lines before match | grep -B 3 "error" app.log |
-C N |
Show N lines before and after | grep -C 3 "error" app.log |
-E |
Use extended regex | `grep -E “error |
-F |
Treat pattern as literal string | grep -F "a.b" file.txt |
-o |
Show only the matched part | grep -o "ERROR[^ ]*" app.log |
-q |
Quiet — no output, just exit code | grep -q "error" app.log |
--color |
Highlight matches | grep --color "error" app.log |
-h |
Suppress filenames | grep -h "error" *.log |
-H |
Always show filenames | grep -H "error" *.log |
sed can be used for search and replace.
find
find searches for files and directories in a directory tree based on various criteria — name, size, date, permissions, type, and more. Unlike ls, which lists a single directory, find walks recursively through everything under a given path.
Basic syntax
bash
1 | find [path...] [expression] |
Simple example
bash
1 | find . -name "*.txt" |
Finds all .txt files under the current directory (.).
The Most Common Filters
By name
1 | find . -name "*.txt" # case-sensitive |
By type
1 | find . -type f # regular files |
By size
1 | find . -size +10M # larger than 10 MB |
Units:
c= bytesk= kilobytesM= megabytesG= gigabytes
By modification time
1 | find . -mtime -1 # modified in the last 24 hours |
By access time
1 | find . -atime -7 # accessed in the last 7 days |
By change time (metadata)
1 | find . -ctime -1 # changed in the last day |
By permissions
1 | find . -perm 644 # exactly 644 |
By owner/group
1 | find . -user caiguu # owned by user |
By depth
1 | find . -maxdepth 1 # only current directory |
By default, find prints matching paths. But you can run commands on each result.
-exec — run a command
1 | find . -name "*.tmp" -exec rm {} \; |
{}= the current file\;= end of command (escaped semicolon)
Quick reference
1 | find . # list everything |
Awk
awk is a programming language designed for text processing. It reads input line by line, splits each line into fields, and lets you perform actions on those fields.
Named after its creators — Aho, Weinberger, and Kernighan — it was created at Bell Labs in 1977. It’s a standard tool on every Unix-like system.
1 | awk 'pattern { action }' file |
Bash Operators
Bash operators are special symbols or keywords that perform operations on:
- Commands (chaining, piping, backgrounding)
- Files and strings (testing conditions)
- Variables (arithmetic, assignment, expansion)
- I/O streams (redirection)
They fall into several categories, covered below.
Command Chaining Operators
| Operator | Name | Meaning |
|---|---|---|
; |
Semicolon | Run commands sequentially, regardless of success |
&& |
AND | Run next command only if previous succeeds (exit 0) |
| ` | ` | |
& |
Background | Run command in the background |
| ` | ` | Pipe |
| ` | &` | Pipe both |
Redirection Operators
| Operator | Meaning |
|---|---|
> |
Redirect stdout to a file (overwrite) |
>> |
Redirect stdout to a file (append) |
< |
Redirect stdin from a file |
2> |
Redirect stderr |
2>> |
Append stderr |
&> |
Redirect both stdout and stderr (overwrite) |
&>> |
Redirect both (append) |
>&2 |
Redirect stdout to stderr |
<< |
Here-document (inline input) |
<<< |
Here-string (inline string input) |
n>&m |
Duplicate file descriptor |
n<&m |
Duplicate input file descriptor |
>&- |
Close a file descriptor |
1 | caiguu@JACKERZHANG-MB0 ~ % if [ "hello" = "world" ]; then echo "equal" ; |
Shebang(#!)
#! is called a shebang (also hashbang or pound-bang). It’s the first two characters of a script file, followed by the path to an interpreter.
1 |
#= hash!= bang- Together: shebang
It tells the operating system which program should execute this file.
How it works
When you run a script directly:
1 | ./script.sh |
the OS does this:
- Reads the first two bytes of the file.
- If they are
#!, it treats the rest of the first line as the interpreter path. - Runs that interpreter, passing the script as an argument.
So this:
1 |
|
is effectively executed as:
1 | /bin/bash ./script.sh |
Some common Shebangs
1 |
|
The #! must be the very first two bytes of the file. No blank lines, no spaces, no comments before it.
Worth mentioning, while executing a bash script, it should be like ./test.sh. If just simply type test.sh, it can’t recognize that it is a program in this directory. It will search $PATH instead.