Missing Semester Lecture 1: Introduction to the Shell


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.
  • 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
2
caiguu@JACKERZHANG-MB0 ~ % date
Sat Sep 12 10:36:30 CST 2026

“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
2
caiguu@JACKERZHANG-MB0 ~ % echo hello world
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
2
3
4
5
6
7
8
caiguu@JACKERZHANG-MB0 ~ % echo hello world
hello world
caiguu@JACKERZHANG-MB0 ~ % echo "hello world"
hello world
caiguu@JACKERZHANG-MB0 ~ % echo hello world
hello world
caiguu@JACKERZHANG-MB0 ~ % echo hello \ \ \ \ world
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
2
caiguu@JACKERZHANG-MB0 ~ % echo $PATH
/Users/caiguu/.bun/bin:/opt/homebrew/opt/node@24/bin:/opt/homebrew/Caskroom/miniforge/base/bin:/opt/homebrew/Caskroom/miniforge/base/condabin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/pkg/env/global/bin:/Library/TeX/texbin:/Applications/Ghostty.app/Contents/MacOS:/Users/caiguu/.turso

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
2
3
4
5
caiguu@JACKERZHANG-MB0 ~ % which date
/bin/date
caiguu@JACKERZHANG-MB0 ~ % which -a python
/opt/homebrew/Caskroom/miniforge/base/bin/python
/usr/local/bin/python

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
2
3
4
5
6
cat file.txt                    # print file contents
cat file1.txt file2.txt # print both, one after another
cat file1.txt file2.txt > out # combine into a new file
cat # read from stdin (type, then Ctrl+D)
cat > newfile.txt # create a file from typed input
cat >> existing.txt # append typed input to a file
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
2
head file.txt        # first 10 lines
tail file.txt # last 10 lines

Also can change the lines of head and tail:

1
2
3
4
head -n 20 file.txt      # first 20 lines
head -20 file.txt # same thing (older syntax)
head -n 1 file.txt # just the first line
head -n 0 file.txt # nothing (useful for testing)
1
2
3
4
tail -n 20 file.txt      # last 20 lines
tail -20 file.txt # same
tail -n 1 file.txt # just the last line
tail -n +5 file.txt # start from line 5 to the end

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
2
3
4
$ grep "error" app.log
2024-01-15 10:23:11 ERROR Failed to connect
2024-01-15 10:25:42 ERROR Timeout after 30s
2024-01-15 10:31:08 ERROR Disk full

The basic syntax is:

1
grep [options] pattern [file...]

These are some common forms:

1
2
3
4
5
grep "pattern" file.txt           # search a file
grep "pattern" file1 file2 # search multiple files
grep "pattern" *.log # search all .log files
command | grep "pattern" # filter command output
grep -r "pattern" dir/ # search recursively
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
2
3
4
find . -name "*.txt"          # case-sensitive
find . -iname "*.txt" # case-insensitive
find . -name "report?.pdf" # ? = any single char
find . -name "report[123].pdf" # [123] = 1, 2, or 3
By type
1
2
3
find . -type f                # regular files
find . -type d # directories
find . -type l # symbolic links
By size
1
2
3
4
find . -size +10M             # larger than 10 MB
find . -size -1k # smaller than 1 KB
find . -size 100c # exactly 100 bytes
find . -size +1G # larger than 1 GB

Units:

  • c = bytes
  • k = kilobytes
  • M = megabytes
  • G = gigabytes
By modification time
1
2
3
4
5
find . -mtime -1              # modified in the last 24 hours
find . -mtime +7 # modified more than 7 days ago
find . -mtime 0 # modified today
find . -mmin -30 # modified in the last 30 minutes
find . -newer reference.txt # newer than reference.txt
By access time
1
2
find . -atime -7              # accessed in the last 7 days
find . -amin -60 # accessed in the last 60 minutes
By change time (metadata)
1
find . -ctime -1              # changed in the last day
By permissions
1
2
3
find . -perm 644              # exactly 644
find . -perm -644 # at least 644
find . -perm /111 # any execute bit set
By owner/group
1
2
3
find . -user caiguu           # owned by user
find . -group staff # owned by group
find . -nouser # no valid owner
By depth
1
2
3
find . -maxdepth 1            # only current directory
find . -maxdepth 2 # up to 2 levels deep
find . -mindepth 2 # skip top level

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
find .                              # list everything
find . -name "*.txt" # by name
find . -iname "*.txt" # case-insensitive
find . -type f # only files
find . -type d # only directories
find . -size +10M # larger than 10 MB
find . -mtime -1 # modified in last 24h
find . -mmin -30 # modified in last 30 min
find . -empty # empty files/dirs
find . -perm 644 # specific permissions
find . -user caiguu # owned by user
find . -maxdepth 2 -name "*.log" # limit depth
find . -name "*.tmp" -delete # delete matches
find . -name "*.sh" -exec chmod +x {} \; # run command
find . -name "*.txt" -exec wc -l {} + # batch mode
find . -path ./node_modules -prune -o -name "*.js" -print

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
2
3
4
caiguu@JACKERZHANG-MB0 ~ % if [ "hello" = "world" ]; then  echo "equal" ;
then> else echo "not equal";
else> fi
not 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
#!/bin/bash
  • # = 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:

  1. Reads the first two bytes of the file.
  2. If they are #!, it treats the rest of the first line as the interpreter path.
  3. Runs that interpreter, passing the script as an argument.

So this:

1
2
#!/bin/bash
echo "Hello"

is effectively executed as:

1
/bin/bash ./script.sh

Some common Shebangs

1
2
3
4
5
6
7
#!/bin/bash              # Bash at a fixed path
#!/usr/bin/env bash # Bash found via PATH (more portable)
#!/bin/sh # POSIX sh (not Bash-specific)
#!/usr/bin/env zsh # zsh
#!/usr/bin/env python3 # Python 3
#!/usr/bin/env node # Node.js
#!/usr/bin/env perl # Perl

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.


文章作者: Jack Zhang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Jack Zhang !
  目录