Shell Filters and System Administration
Prerequisite Knowledge
This lecture builds on the following concepts from earlier lectures. If any feel unfamiliar, review the linked notes before proceeding.
Previously Covered in This Subject
- Creating and inspecting users and /etc/passwd - covered in Lecture 1 (Introduction to Systems Programming)
- File permissions, rwx triplets, and chmod (absolute and symbolic modes) - covered in Lecture 5 (Linux File System - Inodes, File Types, Permissions and Links)
- Inter-user communication: who, tty/pts distinction, and wall broadcasting - covered in Lecture 4 (Linux Commands and File System Navigation) and Lecture 1 (Lab in Practice - 24x7 Cloud Host and User Accounting)
- Linux commands, redirection, and file-system navigation (ls, cat, cp, mv, rm) - covered in Lecture 4 (Linux Commands and File System Navigation)
- The file principle and directory hierarchy (everything is a file) - covered in Lecture 1 (The File Principle - Everything Is a File, Types and Hierarchical Layout)
12.1 Shell Scripts and Assignment Structure
This session sits at the junction of two threads: the shell as a programming language and the shell as a glue for the operating system. It builds directly on the previous two sessions on shell programming and frames the course assignment, which is not an exercise in printing patterns but a practical automation task.
Hook — why should you care? Imagine you must check 500 user accounts to find who can log in interactively, or scan thousands of log lines for one error code. Doing it by hand in an editor is slow and error-prone. A five-line shell script that calls the right filters does it in under a second. That is the shift this lecture makes: from illustrating language features to using them to get real work done.
Intuition — shell script as a recipe. Think of a shell script — a plain text file that lists shell commands plus programming constructs such as loops and conditionals, executed line by line by a shell interpreter such as bash — like a cooking recipe. The ingredients are individual commands (grep, sort, wc, cut); the method steps are control structures (for, if, while). A recipe that only says "stir five times in a star pattern" teaches technique, but a real recipe combines ingredients to produce a dish. Similarly, a useful script orchestrates filters and utilities to search files, transform text, and automate administration, not merely to print shapes on the screen. Where the analogy breaks: unlike a kitchen, the shell reuses the exact same commands interactively and inside scripts, so fluency on the command line transfers directly into scripts, and errors in a script can affect live system files.
Formalize — what a shell script really contains
A shell script has two layers:
- Commands and filters. Every command you can run interactively —
grep,ls,date,who— is a program on disk. A script invokes them as building blocks. Filters are a special subclass that reads stdin or files, selects or transforms lines, and writes to stdout, designed to be chained with pipes.
- Programming constructs. The shell provides
for,while,if/else,case, variables, and functions. The constructs seen in the session illustrate the language features:
for i in 1 2 3 4 5; do
echo -n "\$i "
done
# → 1 2 3 4 5
and a nested loop that prints a star triangle:
for i in 1 2 3; do
for j in \$(seq 1 \$i); do echo -n "* "; done
echo
done
These demonstrate iteration and nesting, but the assignment expects the same constructs applied to purposeful tasks: looping over file lists, testing exit codes, and automating the administrative steps covered from 12.2 onward. Understanding individual commands is therefore central — without knowing what grep -c or grep -w does, you cannot choose the right ingredient for the script.
Worked mini-context: the session contrasted "printing stars" versus "searching files". The former validates syntax; the latter delivers value. A script that counts how many lines in /etc/passwd have /bin/bash as their shell (grep -c "bash\$" /etc/passwd) already does administration that would otherwise require opening the file and counting by eye.
Assumptions & Scope — when this view applies
Assumption: the shell (typically bash on Linux) interprets the script, and each invoked command exists in PATH with expected options. If the shell changes (sh vs bash vs zsh) or a command variant is missing (-w on older grep), behavior may differ.
Scope: shell scripting is ideal for file-centric, line-oriented automation and for gluing existing tools. It is not a replacement for compiled languages when heavy computation, complex data structures, or binary formats are involved. For those, Python or C complements the shell.
What breaks the model: scripts that assume interactive-only commands will behave the same non-interactively (e.g., aliases, prompts) without sourcing the right environment.
Visual intuition: picture a pipeline diagram with two lanes. The top lane shows for → if → echo "*" looping to build a visual pattern — a closed loop producing decoration. The bottom lane shows for file in *.log → grep "ERROR" → wc -l flowing left to right, with files entering at left, filtered lines in the middle, and a count exiting at right. The horizontal axis is data flow, the vertical is purpose. The takeaway: the same loop construct carries very different payloads.
Pitfalls
- Mistaking illustration for objective. Printing
1 2 3 4 5or star pyramids demonstratesforsyntax but is not what will be assessed. The assignment rewards scripts that embed system commands and interpret their output.
- Trying to learn scripting without command fluency. Every command used interactively is also a script building block. Skipping the filter chapters (grep, sort, cut) leaves you with control flow but nothing useful to control.
- Underestimating team coordination. The workload is sized for three; a solo loop over files is easy, but designing, testing, and documenting a complete admin workflow is not. Delay in forming groups directly cuts the preparation time for the command-heavy scripts that follow.
Recap + Bridge — one-line recap and handoff
Shell scripts become practical when programming constructs orchestrate real filters and utilities, not when they merely draw patterns. Hold that framing: the rest of the lecture turns to the most used filter — grep — precisely because it is the command you will call most often inside those scripts. The next section introduces its purpose and syntax.
Real-World & Domain Connection: In operations teams, shell scripts are the overnight operators — log rotation at 2 a.m., daily audit of /etc/passwd for new accounts, or extracting error lines before mailing a report. Civil, mechanical, and CS engineers alike use the same glue role when they automate data cleaning before simulation or analysis. Mastering command-driven scripting is the portable skill that makes the later admin tasks executable without manual intervention.
12.1.1 Role of Shell Programming and Commands
A shell script — a text file of shell commands plus loops and conditionals executed by the shell — becomes practical when it orchestrates filters and utilities rather than drawing shapes. The for loops printing 1 2 3 4 5 and nested star patterns illustrate syntax, but the assessed use is file searching, text transformation, and admin automation, where each interactively practiced command becomes a reusable script component.
12.1.2 Assignment Groups and Practical Focus
The assignment is sized for three students per group, with at most one group of two permitted; all others should have three members. Students not yet on the assignment sheet should form groups promptly and confirm the final list so program allocations can be frozen and preparation time preserved. Early confirmation respects committed peers and aligns with the lecture's pivot to command-heavy scripting, where shared workload matters.
12.2 The grep Filter — Purpose and Syntax
The grep filter purpose — searching passwd without manual edit — illustrates the core value: grep scans passwd without opening the file in an editor, avoiding manual edit risks.
The most frequently invoked building block in shell scripts for text tasks is grep. The session repeatedly heard "grab/grip" — the standard Unix filter grep, short for global regular expression print (g/RE/p in ed), now used far beyond editing to scan any text source.
Hook — the question that motivates grep. You have a file /etc/passwd with hundreds or thousands of accounts. You need to know whether user Anita exists or whether anyone still uses /bin/bash as their shell. Do you open the file in vi and hunt line by line, or ask the system to surface only the lines that contain the pattern? grep is the second answer, and it avoids both manual inspection and unnecessary elevated editing of a sensitive file.
Intuition — grep as a sieve. Picture pouring mixed grain through a sieve that keeps only grains of the size you specified. Input is a stream of lines (from a file, pipe, or stdin); the sieve is your pattern — a description of the characters you want; output is only the lines that contain that pattern. Like a sieve, grep does not modify the input file — it selects and prints. Where the analogy breaks: a real sieve works by physical size; grep works by textual pattern, and with regular expressions that pattern can describe families of strings, not just one literal.
Formalize — filter, pattern, and syntax
A filter reads input (files or stdin), transforms or selects portions, and writes a result to stdout. grep is a selective filter: given a pattern and zero or more files, it scans each line and emits the lines where the pattern occurs, optionally with file names or line numbers.
General form (from grep(1) and T1 §4.1, R2 §3.1):
grep [options] pattern [file ...]
pattern— a string of characters. In the simplest case a literal string such asthisorcase.- More generally a regular expression — a pattern language using metacharacters such as
.(any single character),*(zero or more of the preceding element),?,+,|(in extended mode), character classes[A-Z], and anchors^/\$. The lecture notes most practical uses employ regular expressions: a dot stands for any single character,*repeats, and bracket expressions restrict to alphabets or digits. Options modify matching or output format and are detailed in 12.3. [file ...]— zero or more pathnames; if omitted,grepreads stdin and waits for keyboard input, which is why a missing file argument appears to hang.
Exit status — useful in scripts: 0 if a match was found, 1 if no match, 2 if the file was not found or options are invalid. This makes grep testable in if grep -q pattern file; then ... fi.
Quoting rule: if the pattern contains whitespace or shell metacharacters, quote it ('pattern' or "pattern"); single quotes are safest so the shell does not interpret *, \$, or ^ before grep sees them.
Worked Example — motivating triage on /etc/passwd
You want to know if SAP accounts exist without editing the password database.
grep "SAP" /etc/passwd
# SAP1:x:1005:1005::/home/SAP1:/bin/bash
# SAP2:x:1006:1006::/home/SAP2:/bin/bash
Without grep, you would vi /etc/passwd (which risks accidental edits and may need sudo for read guarantees) and search manually. With grep, the answer appears immediately, even if the file has thousands of entries. The same mechanism applies to any text file — logs, config, or grep_file.
Sense-check: output lines are from the input file verbatim; grep does not reorder or modify them.
Assumptions & Scope — when the syntax applies and when it breaks
Assumption: input is line-oriented text. grep processes each line individually; it does not match across newline boundaries (a pattern never spans two lines).
Assumption: pattern interpretation follows basic vs extended rules. Basic grep treats +, ?, |, () literally unless escaped or -E is used.
Scope: grep is for line selection. Use sed/awk when you need substitution or field-aware transformation, and fgrep/grep -F when you want literal fixed-string search without any metacharacter interpretation.
Failure modes: an unquoted pattern containing shell * may be glob-expanded before grep sees it; a regex starting with - will be parsed as an option unless introduced with -e or --.
Visual intuition: draw a flow left to right: files → grep pattern (sieve) → matching lines to stdout. Annotate the sieve mesh as the pattern: a small literal string lets only exact matches through; a regex mesh with holes shaped ., *, [A-Z] lets families of strings through. The vertical axis is "lines kept vs dropped"; the takeaway is selectivity increases with pattern specificity.
Pitfalls
- Transcribing the name by sound. "grab/grip" in speech maps to the single tool
grep. Writinggrabat the command line yieldscommand not found.
- Forgetting quotes.
grep From \$MAILworks, butgrep From address \$MAILwithout quotes splits the pattern. Usegrep 'From 'when the pattern contains spaces.
- Expecting in-place edit.
grepprints to screen; it never changes the input file, unlikesed -ior an editor save.
- Confusing exit status with output. In a script,
grepmay print nothing yet succeed (exit 0) if a match was suppressed with-q, or print lines yet fail conceptually if you test the wrong status. Test\$?or useif grep -q.
- Directory without
-r. Passing a directory alone (e.g.,grep pattern /etc) reportsIs a directoryand skips it — you must name files explicitly or usegrep -r.
Recap + Bridge
grep is a selective filter that scans lines for a pattern — literal or regular-expression — and prints matches without modifying files, making it the fast alternative to manual editor search. Its exit status makes it script-friendly. With purpose and syntax settled, the next section details the options that reshape what grep reports and how strictly it matches.
Real-World & Domain Connection: System administrators, developers, and data engineers use grep as first triage for log forensics (grep ERROR app.log), config audits (grep "^PermitRootLogin" /etc/ssh/sshd_config), and pipeline filtering (ps aux | grep apache). Combined with pipes, it feeds counts, sorts, and further filters — the exact glue role highlighted in 12.1 for building meaningful shell scripts.
12.2.1 What grep Does
A filter — a program that reads input, transforms or selects parts, and writes a result — in grep's case selects lines containing a given pattern. Given a pattern and a file, grep outputs matching lines, often with file names and line numbers depending on options; with multiple files it indicates which file holds each match. This avoids manual inspection of large files. The motivating example is /etc/passwd with hundreds or thousands of entries: locating a user or group by editing the file is slow and may require privileges, while grep surfaces the answer immediately, and the same mechanism applies to any text file.
12.2.2 Command Syntax and Pattern Types
The general form is grep [options] pattern [file ...] where pattern is a literal string such as this or, more generally, a regular expression — a pattern language using metacharacters ., *, ?, character classes [...], and anchors ^/\$ to describe sets of strings; a dot can stand for any single character, * repeats, and brackets restrict to alphabets or digits. Options modify matching or output and are covered next.
12.2.3 Files, Multiple Files, and Directories
grep accepts a single file, a list, or a shell-expanded set: grep this grep_file searches one file, while grep THIS ./* or grep case *file uses a glob where *file matches any file name ending in file (e.g., grep_file, demo_file) and searches each matched file. When a directory name is passed without a recursive flag, grep reports Is a directory and skips it; to search a directory's files you must give the files themselves via a glob or grep -r.
12.3 grep Options for Output Control
Options — hyphen-prefixed flags that reshape matching and reporting without changing the core search — are what make grep adaptable inside scripts where output format is often more important than raw matches.
Hook — same search, four different answers. Search this in grep_file and you might want: the matching lines, the count 3, just the file names that contained it, or the exact substrings. One pattern, four reporting needs. Options deliver each without changing the pattern.
Intuition — options as output lenses. Think of grep as a camera pointed at text and options as lenses you snap on: -c counts instead of showing, -l shows only file labels, -n adds line-number captions, -i makes the lens color-blind to case, -v shows the negative, -w frames only whole objects, -h removes location stamps. The scene (pattern + files) stays the same; the lens changes what the photograph contains. Break point: lenses compose; some combinations conflict or dominate (e.g., -c suppresses normal line output, -l suppresses line content even if -n is also given).
Formalize — the essential option set (R2 Table 3.2, T1 §4.1)
| Option | Name | Effect | Lecture demonstration | |
|---|---|---|---|---|
-c |
count | Prints count of matching lines, not total word occurrences. A line with two matches still counts as 1. | grep -c this grep_file → 3 |
|
-l |
list files | Lists only names of files containing a match, once each, newline-separated. | grep -l case *file → demo_file, grep_file |
|
-o |
only matching | Prints only the matched substring, one per line, not the whole line. | Isolates pattern for piping to `sort \ | uniq` |
-h |
no filename | Suppresses file-name prefix when multiple files are searched. Default with ≥2 files is file:line; -h removes it. |
Contrasts with default multi-file output | |
-n |
line number | Prefixes each matching line with its line number (n:line). |
this on line 1 case-sensitive; lines 1,2,3,6,7 with -i |
|
-i |
ignore case | Folds case so lower matches upper. Overlaps historical -y. |
this (3) vs -i this (5): captures This, THIS, ThIs |
|
-w |
word | Matches whole words as if surrounded by \< \>. |
Dell vs Dell EMC; North vs Northwest (see 12.5–12.6) |
|
-v |
invert | Prints lines that do not contain the pattern. | grep -v this returns empty lines + non-matching |
|
-e |
expression | Explicitly introduces pattern (grep -e -pattern). Needed when pattern begins with - or for multiple -e patterns (OR). |
grep -e "-error" file |
|
-F |
fixed string | Treats pattern as literal fixed string, no metacharacters (historical fgrep). |
Fast parallel literal search | |
-f |
file of patterns | Reads patterns from file, one per line, matches any. | grep -f common-errors document |
|
-E |
extended regex | Enables extended regex operators `+ ? \ | () (historical egrep`). |
Adds +, ?, alternation |
-s |
silent | Suppresses normal output, shows only errors; useful for exit-status checks in scripts. | grep -s pattern file; echo \$? |
|
-b |
block number | Prefixes byte/block offset; historical, occasionally useful for disk context. | Rare today |
Composition: options combine, e.g., grep -i -c, grep -ivc, grep -n -i THIS. Order after grep does not matter except that -e consumes its argument. The lecture stressed knowing which option yields counts vs lines vs file names, and how -i, -v, -n interact when stacked.
Worked Example — counting and listing on the demo files
Setup: grep_file and demo_file are copies (cp grep_file demo_file) holding words this, This, THIS, case, file, line, plus empty lines. Seven logical lines, three hold literal lowercase this.
Count, case-sensitive:
grep this grep_file # → 3 lines shown
grep -c this grep_file # → 3
Case-insensitive expansion:
grep -i this grep_file # → 5 lines (adds This, THIS/ThIs variants)
grep -i -c this grep_file # → 5
grep This grep_file # capital T, no -i → 1 exact-cap match
List vs show:
grep -l case *file # → demo_file\n grep_file (both have 3 hits each)
grep case *file # → demo_file: ... \n grep_file: ... (lines + filenames)
grep -h case *file # same lines without filenames
Only matching portion:
grep -o "this" grep_file # → one "this" per match line, one per line if line repeats
Invert + count interaction:
grep -v this grep_file # → 2 empty + lines without lowercase this = 4 lines
grep -v -c this grep_file # → 4
grep -i -v -c this grep_file # case-insensitive invert → only the 2 truly empty lines = 2
Sense-check: -c counts lines, so a line with this this on one line would still be 1, not 2; -o would emit two lines in that case, revealing the distinction.
Assumptions & Scope
Assumption: input is text lines; binary files may report Binary file matches or need -a.
Scope: use -F/fgrep when metacharacters must be literal and for many parallel literal strings (its run time is largely independent of number of patterns). Use -E/egrep when you need +, ?, | and grouping.
When it breaks: -w is grep-specific and not universal across all Unix variants (SCO noted); overly broad -i can inflate matches unexpectedly (e.g., THIS matching all caps variants when you wanted only one).
Exit-status note for scripts: with -c or -l, success (0) still means "match found", even though normal line output is suppressed — test if grep -q or check \$?.
Visual intuition: imagine a control panel with toggles: -c flips display from lines to a numeric counter; -n adds a ruler margin with line numbers (1: this..., 2: ...); -h/-l toggle file-name labels on/off. The x-axis is lines of the file, y is "shown". With -c the y collapses to a single number 3; with -l it collaps to file names demo_file, grep_file. Takeaway: options do not move the search; they reshape the report for the next pipeline stage.
Pitfalls
- Confusing
-cwith word count.grep -c thiscounts lines containingthis(3), not occurrences. A line withcase casestill counts as 1. Use-opiped towc -lto count occurrences.
- Expecting
-lto show lines.-lsuppresses line content — you get onlygrep_file. If you need lines plus names, omit-l(default with multiple files) or combine with nothing else that suppresses output.
- Forgetting
-ifolds all case. Without-i,This≠this≠THIS; with-i, all five case variants matched (3 → 5). Assess whether exact case matters before adding-i.
-wsubstring vs word. Without-w,DellmatchesDell EMCandNorthmatchesNorthwest/Northeastas substrings. With-w, only standalone words match. Use-wfor precise token search.
- Inversion double-negatives.
grep -v -ccounts non-matching lines;grep -i -v -cwith case folding changes the count from 4 to 2 in the demo because two lines previously distinct by case are now excluded. Reason carefully about what set you are complementing.
- Pattern starting with
-.grep -error fileparses-eas option; writegrep -e "-error"orgrep -- "-error"instead.
Recap + Bridge
Options reshape matching and reporting — -c counts lines, -l lists files, -o isolates matches, -h/-n control labels and numbers, -i/-w/-v control match strictness, -F/-E/-f choose pattern language — and they compose. The pattern-hunting power comes next: the regular-expression building blocks that options operate upon.
Real-World & Domain Connection: In scripts, grep -c ERROR app.log gates alerts, grep -l "FIXME" src/* finds files needing work, grep -h pattern *.conf merges configs without filename noise, and grep -v "^#" strips comments before counting. Knowing which flag yields a count vs lines vs filenames prevents pipeline bugs where a downstream wc or xargs expects the wrong shape.
Exam note: Combination behavior is directly examinable. Expect output-prediction questions that distinguish counts versus lines versus file names, and that probe how -i, -v, -n interact when stacked (e.g., grep -i -v -c this). Practice tracing a pattern on a given file with and without each flag.
12.3.1 Counting and Listing Matches
Count — -c reports the number of matching lines (not words). Searching this in grep_file shows three lines; grep -c this grep_file reports 3, while file or line as patterns give different counts with exact case sensitivity. List file names — -l lists only names of files that contain a match; grep -l case *file lists demo_file and grep_file because each holds matches, answering "where" rather than "what". Only the matching part — -o prints only the matched substring, one match per line, isolating the pattern for further processing such as sort | uniq -c.
12.3.2 Controlling What Is Displayed
Suppress file names — -h removes the file-name prefix when searching multiple files, showing only matching lines (default with multiple files prefixes each line with file:). Line numbers — -n prefixes n:line; this appears on line 1 case-sensitively, and with -i on lines 1,2,3,6,7. Case sensitivity — -i ignores case, expanding this from 3 to 5 matches to include This/THIS/ThIs; grep -i -c and grep -i THIS grep_file compose. Whole word — -w requires a whole-word match; Dell without -w matches Dell EMC as substring, with -w only standalone Dell qualifies.
12.3.3 Inverting and Specifying Patterns
Invert match — -v prints lines that do not contain the pattern; for this in grep_file it returns the two empty lines plus non-matching lines, so grep -v -c this grep_file is 4 and grep -i -v -c this grep_file is 2 (only empty lines after case-insensitive exclusion). Expression — -e explicitly introduces a pattern, essential when it begins with - or for multiple -e OR patterns. File of patterns — -F treats the pattern as a literal fixed string (no regex), and -f file reads patterns from a file one per line matching any. Extended expressions — -E enables extended regular expressions with + ? | () beyond the basic set.
12.4 Regular Expression Building Blocks
Regular expressions are the pattern language grep interprets — a compact notation for describing sets of strings, built incrementally in the lecture with live file checks.
Hook — from one literal to infinite families. Searching literally for this finds one string. What if you need "any word that starts with A and ends with anything", or "any price that looks like 5. followed by digits"? Literals cannot express that. Regular-expression building blocks let a short pattern describe an infinite set, and grep tests each line for membership in that set.
Intuition — blueprints, not photographs. A literal pattern is like a photograph of one house — it matches only that house. A regular expression is a blueprint: . means "any material allowed here", * means "repeat the previous piece zero or more times", [A-Z] means "any capital letter allowed here". [A-Z][A-Z][A-Z] is a blueprint for "three capitals in a row". The more flexible the blueprint, the more houses match. Break point: a blueprint that says "zero or more" can match nothing at all — .* matches the empty string — which surprises beginners who expect at least one character.
Formalize — atomic metacharacters and closure
Dot . — any single character. . matches exactly one character position, including letters, digits, punctuation, space and tab (line-oriented, never newline). A single dot therefore consumes one slot. a.c matches abc, a c, a-c but not ac.
Star * — closure (zero or more of the preceding element). * does not mean "any string" by itself; it repeats the immediately preceding atom zero or more times, as long as possible (greedy). Key compositions:
.*— dot is any character, star repeats it zero or more times → any string including empty, including spaces/tabs. This is the bridge that connects two fixed fragments across arbitrary intervening text (this.*file).s*— zero or morescharacters (this*filemeansthi+ zero or mores+file, e.g.,thisfile,thissfilewould match if no space intervenes).[A-Z]*— zero or more uppercase letters.
Critical clarification from lecture: * alone does not mean "any string including spaces" in basic interpretation. In this*file without a dot, * applies to the preceding s and was described pedagogically as covering alphanumerics but not space. To bridge a space between this and file you need the dot: this.*file includes spaces. Demonstrated: grep "this*file" grep_file gave no output while grep "this.*file" grep_file matched this ... file.
Character classes [...] — one character from a set. Square brackets define a character class: any one character from the set inside.
[A-Z]— one uppercase letter[a-z]— one lowercase letter[A-Za-z]— one alphabetic character[0-9]— one digit[A-Za-z0-9_]— word character (same spirit as\w)[AG]at pattern start —AorGin first position;[ABCD]/[A-D]— any one of those letters[AB].*— first two characters areAthenB, then anything (.*bridges remainder)
Repetition on classes: [A-Z]* or [A-Za-z]* applies * to the class → zero or more characters from that class. Distinction: [A-Za-z]* alone matches any alphabetic string (including empty); [A-Za-z] without * matches exactly one alphabetic character. The count of consecutive class atoms matters: [A-Z][A-Z][A-Z] requires three consecutive capitals; grep "[A-Z][A-Z][A-Z]" table.doc probes exactly that. Without -i, lowercased northeast/southeast were excluded; with -i all three-letter alphabetic runs matched.
Coining the distinction: to require at least one character from a class, the classic basic-regex idiom is class followed by class*, e.g., [A-Za-z][A-Za-z]* for one or more letters (extended regex would write [A-Za-z]+).
Anchoring preview: character classes are atoms that compose with anchors (^/\$) and escaping, covered in 12.5.
Worked Example — probing three capitals in table.doc
File table.doc contains lines like NW Northwest 3.98 ..., NE Northeast 3.77 .... The pattern:
grep "[A-Z][A-Z][A-Z]" table.doc
Step-by-step: [A-Z] = one capital (position 1), second [A-Z] = capital at position 2, third [A-Z] = capital at position 3. Only lines with three consecutive capitals at any position match. Initially Northeast/Southeast lowercased to northeast fail the second/third cap requirement, so only abbreviation fields like NW , SW etc. were candidates but length mattered — after adjustment the count clarified. Adding -i:
grep -i "[A-Z][A-Z][A-Z]" table.doc
now folds case, so any three alphabetic characters consecutively at that locale match regardless of case, and all lines matched.
Second check:
grep "[A-Z][a-z]" table.doc
After lowercasing manipulations, only two lines retained a capital followed by lowercase at the tested column, returning two matches. Sense-check: removing one [A-Z] would change the required length, and grep "[A-Z]*" would match even empty strings at every line (often not what you want).
Assumptions & Scope
Assumption: regex is applied per line, not across lines; .* never crosses newline, and the match is substring by default (need ^/\$ to anchor).
Basic vs extended: In basic grep, +, ?, |, () are literals unless escaped or -E is used; [A-Z]* is basic-legal, [A-Z]+ needs -E.
Scope: use [A-Za-z0-9_] or \w for token-like usernames that include underscores/digits; use [^...] negation (next subsection) when you want "anything except".
Failure mode: * applied to a class that can match empty ([A-Z]*) will match zero characters — grep "[A-Z]*" file matches every line (including empty). To force at least one, double the atom as above.
Visual intuition: draw three adjacent boxes labeled [A-Z] [A-Z] [A-Z] forming a stencil. Slide the stencil along a line N o r t h w e s t; only positions where three consecutive slots are all capitals light up. Replace one box with .* — the stencil now has a stretchy middle that can expand to any length including zero. The x-axis is character position, shape is "fixed vs stretchy". Takeaway: dot-star is the stretchy glue; bracket triples are rigid length checks.
Pitfalls
- Reading
*as "any string".*repeats only the preceding element.this*file≠this.*file. The former repeatss; the latter bridges with any characters including spaces. This was the live demo that produced no output without the dot.
- Forgetting
.*matches empty.grep "a.*b" filematchesab(zero characters between) as well asa---b. If you need at least one, usea..*bor extendeda.+b.
- Confusing single-character vs string.
[A-Za-z]is one letter,[A-Za-z]*is zero or more letters (a string).grep "[A-Za-z]"vsgrep "[A-Za-z]*"on a file with numbers will both match lines with any letter, but semantics differ for empty and multi-char expectations.
- Shell vs regex brackets. The shell also uses
[...]for globs, but inside regex[^...]negation syntax and escaping of]/-/^differs (T1 §4.1 warns about placement of-and]to avoid ambiguity).
Recap + Bridge
Building blocks: . = one any, * = zero-or-more of previous (so .* = any string), [...] = one of set with ranges and negation. Composition and repetition on classes controls length, and the classic trap is reading * as any string without its preceding dot. With atoms settled, the next section adds position (^/\$), literalization (\), and word constraints, plus shorthands and negation that make these blocks practical.
Real-World & Domain Connection: These atoms underpin every log filter and validator: grep "[0-9][0-9]:[0-9][0-9]" syslog finds timestamps, grep "[A-Z][a-z]*" extracts capitalized words, and grep ".*ERROR.*" is the canonical "contains ERROR anywhere" bridge used before piping to counters and alerts.
12.4.1 Single-Character and Any-String Metacharacters
A dot . matches any single character (space/tab included) and consumes exactly one position. .* combines dot with * (zero or more of preceding) to match any string including empty, bridging two fixed fragments. The lecture emphasized * alone does not mean any string including space: this*file without a dot applies * to the preceding s (described as alphanumerics but not space) and gave no output, while this.*file with dot-star bridges spaces and matched this ... file.
12.4.2 Character Classes and Ranges
Square brackets define a character class — any one character from the set: [A-Z] one uppercase, [a-z] one lowercase, [A-Za-z] one alphabetic, [0-9] digit, [A-Za-z0-9_] word-like, [AG] at start means A or G in position 1, [ABCD]/[A-D] any of those letters, [AB].* means A then B then anything. Applying * to a class ([A-Z]*, [A-Za-z]*) means zero or more from that class. grep "[A-Z][A-Z][A-Z]" table.doc probes three consecutive capitals; without -i lowercased entries are excluded, with -i all three-alpha runs match.
12.4.3 Character Class Shorthands and Negation
Shorthands (often via extended/PERL-compatible modes, cited as extended classes) include \d digit ([0-9]), \D non-digit, \w word character ([0-9A-Za-z_]) useful for usernames with underscores/digits, \W non-word, \s whitespace, \S non-whitespace. Negation inside a class uses a leading caret ^ inside brackets: [^0-9] matches any character that is not a digit, [^A-Z] any non-uppercase; the placement of ^ is decisive, as explored in Q&A.
12.5 Anchors, Escaping, and Word Matching
Position and literalization turn the building blocks into precise tools: anchors say where in the line, escaping says literally that, and word-mode says whole token.
Hook — the same characters, three different jobs for ^. Meet ^. In ^SAP it means "start of line". In [^0-9] it means "not a digit". In SAP^ it is literal ^. One symbol, three meanings depending on where it sits. Mastering that placement is the difference between "find all accounts named SAP1" and "find every line that contains a non-digit" — the exact mix-up the lecture staged live.
Intuition — anchors as bookends, escapes as quotes. Think of ^ and \$ as bookends that do not take shelf space: they assert "this end of the shelf" without occupying a book slot. ^SAP means the line's left bookend is S, bash\$ means the right bookend is h of bash. Escaping with \ is like putting quotes around a wild character: . normally means "any book", \. means "a book literally printed with a dot on its cover". Whole-word mode -w is asking for a book that sits alone between spaces/punctuation, not squeezed inside another title. Break point: bookends consume no characters, so ^\$ matches an empty line, and 5\. is two characters (5 + literal dot), not three.
Formalize — anchors, escapes, word and extended modes
Anchors — zero-width position assertions (T1 Table 4.1, R2 Table 3.1):
^outside a bracket, at pattern start, anchors to beginning of line.^SAPmatches lines starting withSAP. Demo on/etc/passwd:grep "^SAP" /etc/passwd→ onlySAP1,SAP2.^A→Anitaetc.^U→ the singleUbuntu-related entry.\$outside brackets, at pattern end, anchors to end of line.bash\$matches lines ending withbash. On/etc/passwdthis isolates interactive shells:grep "bash\$" /etc/passwd→root,ubuntu,SAP1,SAP2,Anita,Anupwhilenologinentries are excluded. Converselynologin\$lists non-interactive system accounts. In basicgrep\$is often escaped as\$in examples (bash\$) due to shell protection; inside single quotes'\$'and\$both anchor.- Both together require full-line match:
^pattern\$means the entire line is exactly the pattern. Classic empty-line probe is^\$.
Escaping metacharacters — \ removes special meaning:
Characters . * [ ^ \$ have regex meaning; to match them literally, prefix with \. The canonical example is a decimal point: . alone is "any char", so a literal . requires \..
5\.→ literal5followed by literal.— the two-character sequence5.5\..→5+ literal.+ one any character (wildcard dot) →5.plus at least one more char. Intable.docthis hits column four where values like53.97or5.95contain5.+ digit, but not bare5columns.5\.alone (no trailing dot) matches any word beginning with5.and continuing arbitrarily; with-wrequiring a whole word5.it produces no output because no word is exactly two characters5..- Reminder:
\escapes the next char, so\.is literal dot,.stays wildcard; similarly\[literal bracket,\^literal caret,\$literal dollar.
Whole-word matching — -w (R2 Table 3.2):
-w matches only whole words, as if the pattern were surrounded by \< \> (or \b in PCRE). Without -w, grep North table.doc matches Northwest, Northeast, Northern as substrings. With grep -w North table.doc only lines where North appears as a separate word (bounded by non-word characters) qualify, so compound directions are excluded.
Extended vs basic — -E, -F (T1 §4.1 fgrep/egrep lineage):
- Basic regex (default
grep): core^ \$ . * []and grouping@@BNMATH434bf885a0c24c2daa984466c10f12f9@@with\1tags, repetition\{m,n\}. - Extended (
grep -E, historicalegrep): adds+(one or more),?(zero or one),|(alternation/or),()grouping without backslashes: e.g.,egrep "(North|South)west"orgrep -E "5\.[0-9]+"for5.plus one or more digits. - Fixed-string (
grep -F, historicalfgrep): no metacharacters, parallel literal search for many strings.
Shorthands & negation placement (recap from 12.4):
\d ≡ [0-9], \w ≡ [A-Za-z0-9_], \s whitespace; negated \D \W \S. Negation [^0-9] uses ^ inside as first char after [ to mean "not". [^A-Z] = non-uppercase. Crucially ^ outside means anchor, inside leading means negation.
File-based hunt nuance:
[A-Za-z]* matches any alphabetic string (including empty); [A-Za-z] without * matches exactly one alpha. Therefore grep "[A-Z][a-z]" table.doc after lowercasing returned only two lines with a capital+lowercase pair, while [A-Z][A-Z][A-Z] required three caps.
Worked Example — isolating interactive accounts and literal-dot searches
Interactive shell audit:
grep "bash\$" /etc/passwd # or grep 'bash\$'
# root:x:0:0::/root:/bin/bash
# ubuntu:x:1000:1000::/home/ubuntu:/bin/bash
# SAP1:x:1005:1005::/home/SAP1:/bin/bash ... etc.
grep "nologin\$" /etc/passwd
# daemon:x:1:1::/usr/sbin:/usr/sbin/nologin ... many system accounts
Change one side: grep "^root" /etc/passwd → only the root line; grep "^bits" /etc/passwd → provisioned cohort (see 12.8). Sense-check: bash\$ vs bash — the former excludes lines where bash appears mid-line, the latter would also match comments containing bash.
Literal-dot table probe: File table.doc columns: NW Northwest 3.98 ..., S Southern 5.95 ...
grep "5\.." table.doc
# S Southern 5.95 6 and 23 → 5 . 9 (literal dot + any char 9)
# W Western 53.97 ... → 5 3 . 9 ... but wait? 5\.. matches 5 . 3? Actually 53.97 contains "5" then "3" then "."? No. Correct: 53.97 contains "3.9" not "5..". So line with 53.97 matches because characters "...53.97..." contain substring "3.9"? No. Better: 5\.. on "53.97" matches "3.9"? Confusion. Real demo: 5\.. matched column four where value starts "5." then digit, so "5.95" qualifies (5 . 9). 53.97 also qualifies because it contains "5" at position 1 of "53.97"? Actually "53.97" is "5" + "3" + "." + "9"... The pattern 5\.. needs "5" then literal "." then any char. In "53.97", characters are '5','3','.','9' — there is no "5." adjacency, so it would not match. Lecture's "53.97" example therefore illustrates a different column interpretation; column four values that did match were those literally starting "5." such as 5.95, 5.678.
Clarified: 5\.. needs literal dot immediately after 5; 53.97 lacks that adjacency and would not be hit — the matched rows were those with 5.95 style entries, confirming column four is the source identified by Dinesh. Removing trailing dot to grep "5\." table.doc matches any 5. plus continuation, still column four; grep -w "5\." table.doc then yields no output because no word is exactly 5. alone. Sense-check: escaping decides: 5. vs 5\. — dot wildcard vs literal dot — and trailing . decides "at least one more char after dot" vs "any continuation length".
Assumptions & Scope
Assumption: locale influences [A-Z] range ordering; LC_ALL=C gives ASCII ordering expected in examples.
Scope: anchors are zero-width; they do not consume a character, so ^\$ can match empty lines and ^A.*Z\$ forces the whole line from A to Z.
When to use extended: need + ? | () — use grep -E; need literal ./* — use grep -F or escape; need word boundaries portably — prefer grep -w over manual \< \> which varies by implementation.
Visual intuition: sketch a line as a shelf from ^ (left end) to \$ (right end). Place label SAP glued to left bookend for ^SAP; bash glued to right for bash\$; \. as a dot sticker on a book cover vs . as a transparent field that can be any cover. Whole-word -w draws word-boundary fences (| non-word) around the pattern. The x-axis is character position; y is "must be at edge vs anywhere". Takeaway: moving ^ inside brackets flips its meaning from edge to negation.
Pitfalls
- Caret placement.
^[0-9](outside) = line starts with digit →table.docprinted nothing because no line starts with a digit.[^0-9](inside leading) = any non-digit → every line has non-digits, so all lines match. Swapping placement completely changes output, the exact Q&A trap in 12.6.
- Dollar escaping and quoting. In double quotes or unquoted,
\$may be expanded by the shell; always single-quote anchors or escape as\$. Writegrep 'bash\$'orgrep "bash\$"notgrep bash\$unquoted.
5.vs5\.vs5\...5.=5+ any char (e.g.,5x,53),5\.=5.literal,5\..=5.literal + one any char. Mixing them explains why removing the trailing dot changes from "requires one char after dot" to "any continuation", and why-wwith5\.finds nothing.
-wvs substring. Forgetting-wwhen searchingNorthreturnsNorthwest/Northeastsurprises; adding-wwhen you actually want substrings would miss compounds.
- Basic vs extended surprise. Writing
grep "a+b" fileexpecting "one or more a" fails in basic mode (matchesa+bliteral); needgrep -E "a+b"orgrep "a\+b".
Recap + Bridge
^/\$ assert line edges without consuming characters, \ literalizes metacharacters (\. for a real dot), -w enforces whole-word boundaries, and -E/-F choose regex dialect. The decisive detail is placement — ^ outside vs inside brackets — and escaping — dot vs \.. Armed with these, we can trace the full worked file searches that follow.
Real-World & Domain Connection: Daily admin audits rely on anchors: grep "^bits" /etc/passwd counts cohort accounts, grep "bash\$" separates interactive from nologin\$ system accounts, and grep "5\." style literal-dot escaping is mandatory when grepping version numbers (1\.2\.3), IP addresses (192\.168\.1\.), or CSV decimals where a wildcard dot would over-match.
Exam note: Anchors, escaping, .* vs *, and caret inside vs outside are the pattern-prediction focus. Be ready to trace a given pattern on a provided file and explain why a variant with or without dot/backslash or with moved ^ gives a different result count.
12.5.1 Beginning-of-Line and End-of-Line Anchors
Anchors assert position without consuming characters. ^ outside brackets at pattern start anchors to beginning of line: ^SAP matches lines starting with SAP; on /etc/passwd grep "^SAP" /etc/passwd returns SAP1/SAP2, ^A returns Anita etc., ^U the Ubuntu entry. \$ anchors to end of line: bash\$ matches lines ending with bash, isolating /bin/bash interactive users (root, ubuntu, SAP1 etc.) while excluding nologin, and nologin\$ conversely lists non-interactive accounts. Both may combine (^pattern\$) for full-line matches such as ^\$ for empty lines.
12.5.2 Escaping Metacharacters
Because . * [ ^ \$ are special, a literal match requires \. Matching a decimal point requires \.: 5\. is the two-character sequence 5 + literal dot. In table.doc with columns NW Northwest 3.98 ..., grep "5\.." is read as 5 literal, \. literal dot, . any single char after the dot, thus matching strings starting 5. plus at least one following character (e.g., 5.95) found in column four — identified by Dinesh as the source — but not bare 5. Removing the trailing dot to 5\. means "word begins 5. and may continue", still column four but longer; grep -w "5\." requiring whole word 5. alone then yields no output because no word is exactly 5.. Students are reminded \ escapes the following char: \. literal dot vs . wildcard.
12.5.3 Whole-Word Matching and Extended Expressions
Whole word — -w was examined with North: without -w, grep North table.doc also matches Northwest/Northeast as substrings; with grep -w North only lines where North stands alone as a separate word qualify. Extended vs basic — basic regex uses the core set, while extended (-E) adds +, ?, alternation | and grouping () with richer repetition; the lecture listed -E for that and -F for fixed-string matching. File-based hunt — [A-Za-z]* matches any alphabetic string, [A-Za-z] alone one alpha; the count of consecutive class atoms controls leading characters, so grep "[A-Z][a-z]" table.doc after lowercasing returned only two lines with capital+lowercase.
12.6 Worked grep Examples — File Searches and Table Document
This is the hands-on core where the filter, options, and regex atoms are exercised together on two deliberately small files and one structured table. The aim is not to memorize outputs but to learn to trace a pattern line by line.
Hook — can you predict the output before running? Given grep_file with seven lines (some with this, some capitalized, two empty) and table.doc with eight compass rows and numeric columns, can you say whether grep -w "5\." prints anything, or why grep "^[0-9]" prints nothing? The lecture used live polling — Dinesh, Rajesh and others answering — to turn output prediction into the examinable skill.
Intuition — grep as a line-by-line judge. Picture each line entering a courtroom where the pattern is the law: the judge (regex engine) answers "does this line contain a substring that fits the law?" independently for each line. Multi-line globs (*file) simply bring more defendants; ^/\$ add "must be at the wall" conditions; -i tells the judge to ignore case; -v asks for acquittals. The table document adds columns visually, but the judge sees only a flat string per line — column position is not encoded in the law, which is why adding a 5. entry in another row made that row match too. Break point: the judge sees lines independently; there is no memory of previous lines or column numbers unless the pattern itself encodes them.
Formalize — the three file sets
grep_file / demo_file — controlled corpus. Created by pasting multi-line content, then cp grep_file demo_file. Identical initial contents containing words this, This, THIS (and ThIs variant), case, file, line, plus two empty lines. Total logical lines ≈7, with three holding literal lowercase this. This small size lets counts be verified by eye via cat.
table.doc — structured columns. Built interactively via cat > table.doc with eight rows:
NW Northwest 3.98 3 and 34
W Western 53.97 5 and 23
SW Southwest 2.78 2 and 18
S Southern 5.95 6 and 23
SE Southeast 2.99 6 and ...
NE Northeast 3.77 63
N Northern 4.96 5 ...
C Central 5.678 3 and 45
... (values tweaked live)
Columns: (1) abbreviation, (2) full direction name, (3) decimal d.dd or dd.dd, (4) subsidiary integers. The pattern-hunting value is that column 3 values contain digit . digit, column 4 may contain bare digits, so 5\.. vs 5\. probes which column is hit.
Glob semantics. Pattern *file in shell context means "file name ending in file", so grep case *file expands to grep case demo_file grep_file (desktop directories reported Is a directory and skipped). The pedagogical point: to search a directory's files, give the files via glob, not the directory alone.
Worked Example — basic searches and counts on grep_file
Step 1 — setup:
cat grep_file
# line1: this is a case file.
# line2: This is ...
# line3: THIS ...
# line4: (empty)
# line5: (empty)
# line6: ThIs line has ...
# line7: another case line with file.
# (illustrative; lecture had 3 lowercase this lines)
cp grep_file demo_file
Step 2 — literal search:
grep this grep_file
# → prints the 3 lines containing lowercase "this" as substring
Step 3 — multi-file glob:
grep THIS ./* # shell expands ./* to all files in .
# demo_file:THIS ...
# grep_file:THIS ...
# grep: ./Desktop: Is a directory (skipped)
grep case *file
# demo_file: this is a case file.
# demo_file: another case line with file.
# demo_file: ...
# grep_file: (same 3 lines with prefix grep_file:)
File names prefix when ≥2 files are searched; with one file they are absent unless -H forced.
Step 4 — case sensitivity ladder (counts are lines, not words):
grep this grep_file # 3 lines
grep -c this grep_file # 3
grep -i this grep_file # 5 lines (adds This, THIS, ThIs)
grep -i -c this grep_file # 5 (also grep -ic)
grep This grep_file # 1 (exact cap T, no -i)
grep -c line grep_file # 3 (three lines hold word line)
grep -n this grep_file # e.g., 1:this is a case file. (only line 1 in case-sensitive)
grep -n -i this grep_file # 1:... 2:... 3:... 6:... 7:...
Sense-check: -c counts lines with at least one match, so even if a line held this this, it would still be 1; pipeline grep -o this | wc -l would count occurrences.
Step 5 — anchored and composite:
grep "^this" grep_file # 1 line — only line starting lowercase this
grep -i "^this" grep_file # 3 lines — folds This/THIS at start
grep "file\$" grep_file # 0 — lines end "file." with trailing dot, so \$ fails
grep "file\." grep_file # 2 — lines ending literal "file."
grep "^this.*file\.\$" grep_file # this at start, .* bridges spaces, literal file. at end → matches qualifying line(s)
grep "^this*file" grep_file # 0 — star repeats s only, cannot bridge space (see Q&A)
grep -h "file" grep_file demo_file # same lines without filename prefix (vs default with prefix)
Step 6 — table.doc probes (trace each pattern atom):
grep "5\.." table.doc
# → lines where substring "5" + literal "." + one any char occurs
# S Southern 5.95 ... (5 . 9)
# C Central 5.678 ... (5 . 6)
# Dinesh identified column four as source because column four holds 5.95 style values; 53.97 would not match "5." adjacency
Adding a 5. entry in another row's column two then made that row also match, confirming per-line scanning, not column-number awareness.
grep "5\." table.doc # any "5." plus continuation
grep -w "5\." table.doc # no output — no word is exactly "5." alone
grep "^[WE]" table.doc # lines starting W or E → Western, Eastern entries (Rajesh correct)
grep "^[WE].*" table.doc # same plus anything after
grep "^[0-9]" table.doc # 0 — no line starts with digit
grep "[^0-9]" table.doc # all lines — every line has at least one non-digit
grep "^[^0-9]" table.doc # all lines — every line starts with non-digit (interface of two uses)
grep "[A-Z][A-Z][A-Z]" table.doc # three caps consecutive
grep -i "[A-Z][A-Z][A-Z]" table.doc # with -i all lines match (folded)
grep "[A-Z][a-z]" table.doc # after lowercasing northeast/southeast, only 2 lines retain Cap+lower at tested position
Sense-check for table: each pattern is tested per line; ^ checks position 1 only; 5\.. requires literal dot adjacency, so bare 5 in column four fails.
Assumptions & Scope
Assumption: files are small and ASCII, locale C; grep is basic mode unless -E/-F specified; shell globs have expanded before grep sees arguments.
Scope: these demos generalize: the same grep -i -c, anchored ^bits, and 5\. escaping apply to /etc/passwd, logs, and CSVs on any line-oriented text.
Limits: patterns do not express column numbers directly — "column four" is a human interpretation; the regex sees only a character stream. For column-aware extraction use awk -F ' ' '{print \$4}' or cut.
Visual intuition: show grep_file as 7 stacked horizontal strips, three highlighted for this (case-sensitive) and five for -i this. Overlay ^this as a left-edge highlighter touching only strip 1; file.\$ as right-edge touching strips ending with dot. For table.doc, draw columns as faint vertical guides but emphasize the regex scans left-to-right across the whole line, so 5\.. highlight falls in column four only where literal 5. occurs. Takeaway: the pattern's yes/no is per strip, not per column box.
Pitfalls
- Counting lines vs occurrences.
-cis lines, not words — a line with two hits counts as one.
- Star vs dot-star.
this*file(star ons) cannot bridge a space;this.*file(dot-star) can. Live demo gave zero vs success, the exact misconception corrected.
- Empty-line surprises.
grep -v thisreturns two empty lines plus non-matching; students often forget empty lines are lines.
- End-anchor with trailing dot.
file\$fails when lines endfile.; needfile\.orfile\.\$.
- Caret placement.
^[0-9]vs[^0-9]confusion — see Q&A; placement outside vs inside brackets flips meaning.
- Glob vs regex
*.*fileas shell glob (file name ending in file) ≠ regex*(repetition). Mixing contexts leads to "why does*filework ingrep case *file?" — because the shell expands it before grep.
- Assuming column semantics.
5\..hitting column four is because that's where5.happens to appear; adding5.elsewhere makes another column match, proving no column awareness.
Recap + Bridge
File searches combine corpus (grep_file/demo_file/table.doc), counting (-c/-i/-v), anchoring (^/\$/^.*\.\$), and literalization (\.). The examinable skill is to trace each atom: dot vs literal dot, star vs dot-star, ^ outside vs inside. With worked tracing complete, the next sections pivot from text selection to the privilege model that governs which files you may even read or modify.
Real-World & Domain Connection: The same patterns audit real systems: grep "^2021" /etc/passwd counts cohort accounts, grep "192\.168\." auth.log finds local addresses (literal dots), grep -w ERROR app.log | grep -v -i timeout isolates non-timeout errors. Mastering per-line prediction makes script behavior predictable before deployment.
12.6.1 Basic Searches with grep_file and demo_file
A text file grep_file was created by pasting multi-line content and duplicated via cp grep_file demo_file; both initially held identical lines with this, This, THIS, case, file, line, and empty lines. grep this grep_file returned the three lines containing lowercase this as substring, confirming three occurrences. A multi-file glob such as grep THIS ./* or grep case *file (where *file means any file name ending in file, matching grep_file and demo_file) searched both files, reported desktop entries as Is a directory and skipped them, and prefixed matches with file names; case contributed three matching lines per file with file names included.
12.6.2 Case-Sensitive versus Case-Insensitive Counts
Case sensitivity was contrasted step by step: grep this grep_file → three lines; grep -c this grep_file → 3; grep -i this grep_file → five lines including This, THIS, ThIs variants; grep -i -c this grep_file (or grep -ic) → 5; grep This grep_file (capital T, no -i) → 1; grep -c line grep_file → 3. Emphasis: -c counts lines containing at least one match, not total word occurrences — a line with multiple occurrences still counts as one.
12.6.3 Anchored and Composite Pattern Searches
Start anchor — grep "^this" grep_file matches lines beginning this, one line in the sample, demonstrating ^ at line start. End anchor — grep "file\$" grep_file vs grep "file\." grep_file contrasts end-of-line vs literal dot: file\$ alone yields no output because lines end file. with trailing dot; file\. succeeds on two lines ending file.. Both anchors — grep "^this.*file\.\$" grep_file requires this at start, .* bridging spaces, and file. at end; switching .* to * alone produces no matches because * without dot cannot bridge spaces, reinforcing the .* lesson. Case-insensitive anchored — grep -i "^THIS" or grep -i "^this" expands start-anchored to three lines. grep "file" locates substring anywhere, grep "^file" restricts to beginning.
12.6.4 Table Document Exploration and Classroom Q&A
A structured file table.doc built via cat > table.doc with rows:
NW Northwest 3.98 3 and 34
W Western 53.97 5 and 23
SW Southwest 2.78 2 and 18
S Southern 5.95 6 and 23
SE Southeast 2.99 6 and ...
NE Northeast 3.77 63
N Northern 4.96 5 ...
C Central 5.678 3 and 45
... (values adjusted live)
Columns: abbreviation, full name, decimal with dot, subsidiary integers.
Pattern walkthroughs: grep "5\.." table.doc matches 5 literal, \. literal dot, . any char after — column four source, so 5.95/5.678 rows match but bare 5 does not; Dinesh identified column four and reasoned that it holds 5 before the dot. Adding a 5. entry in another row made that row match, confirming per-line scanning and no column-position encoding. grep "5\." table.doc matches any word beginning 5. with continuation; grep -w "5\." yields no output because no word is exactly 5. alone. grep "^[WE]" table.doc matches lines starting W/E (Western, Eastern — Rajesh); grep "^[WE].*" extends with anything after. grep "^[0-9]" vs grep "[^0-9]" illustrates caret placement: the former prints nothing (no line starts digit), the latter shows all lines (every line has a non-digit). grep "[A-Z][A-Z][A-Z]" table.doc probes three consecutive capitals; after lowercasing northeast/southeast they are excluded, returning only fully capitalized abbreviations; after manipulations only two lines remain for [A-Z][a-z].
Q: What will grep "5\.." table.doc output and which column does it hit? Why does it not show the bare 5 columns? A: It hits column four because column-four values contain 5 immediately followed by a literal dot and then another character — e.g., 5.95 or 5.678 (pattern: 5 literal, \. literal dot, . any following char). Bare 5 without a dot fails the \. requirement, so it is not returned. Adding a 5. entry elsewhere would make that line match too, proving scanning is per-line, not column-aware.
Q: If * means any string, why does grep "this*file" grep_file give no output while grep "this.*file" grep_file succeeds? A: * repeats only the immediately preceding element. In this*file the star repeats the final s (described as alphanumeric repetition but not covering space), so it cannot bridge the space between this and file. .* means "any character, zero or more times", which includes spaces, so this.*file bridges the gap and succeeds. Without the dot, the pattern cannot span the space, hence no match.
Q: Does .. mean parent directory here? A: No. Inside a regular expression .. means two wildcards, each matching any single character. The parent-directory meaning (..) applies to filesystem paths, not to the pattern argument of grep. Confusing the two caused the error for grep "5\..", where the suffix dots are regex wildcards, not directory navigation.
Q: What does each piece of 5\. and 5\.. mean? A: 5 is literal five. \ escapes the next character so \. matches a literal dot, not the wildcard. A trailing . without backslash is the wildcard for any single character. Thus 5\. matches the two-character sequence 5 plus dot. 5\.. matches 5 plus dot plus one additional arbitrary character after the dot.
Q: Why does grep -w North table.doc behave differently from grep North table.doc? A: Without -w, North is found as a substring inside Northwest, Northeast, Northern. With -w, the whole-word condition requires North to appear as a separate word bounded by non-word characters, so compound direction names are excluded and only a line with standalone North qualifies.
Q: What about grep "^[0-9]" versus grep "[^0-9]" on table.doc? Why does the second show all lines? A: ^[0-9] with ^ outside the class asserts beginning-of-line followed by a digit. No line in table.doc starts with a digit, so it prints nothing. [^0-9] with ^ inside as leading char negates the class: "any character that is not a digit". Every line contains non-digit characters, so all lines match. The placement of ^ completely changes the meaning — the exact terminology contrast the lecture highlighted.
Teaching moments preserved
- Misconception correction —
*vs.*: Students read*as "any string including spaces". The correction:*repeats only the preceding char;.*is needed to include spaces. Demothis*file(fail) vsthis.*file(success) cements the distinction.
- Rejected analogy —
..as parent directory: The filesystem meaning was rejected inside regex;..is two wildcards. Source of error for5\..suffix was flagged explicitly.
- Terminology contrast —
^outside vs inside[]:^outside = anchor (beginning of line),^as first char inside[^...]= negation (not in set). The pairedgrep "^[0-9]"vsgrep "[^0-9]"demo is the canonical illustration.
12.7 Superuser Status and Privileged Operations
Text selection is only useful if you are allowed to read the files — and many operations require more than reading. The session pivots from filters to the privilege model, demonstrated live on a local virtual machine via SSH because shared educational hosts intentionally withhold superuser rights.
Hook — who may change the clock? Anyone can run date to read the time. Try date -s "2022-11-05" to set it and you are denied. The same binary, the same file system, but mutation is gated. The superuser is the role that passes that gate — and the lecture proves it by flipping the calendar from Nov 6 to Nov 5 and back with sudo.
Intuition — superuser as master key. Picture a building where every room (file, process, clock, network) has a lock. A regular user has a key to their office and shared lobbies. The superuser (root, UID 0) is the master key: it opens any room, changes any lock, and evicts any occupant. su means stepping into the master-key office (becoming another user, default root) and staying there; sudo means borrowing the master key for one specific errand, authenticated by your own password, then returning it. The prompt changing from ubuntu@...\$ to root@...# is the visual cue you now hold the master key. Break point: power without discipline destroys: running rm -rf / as root erases the system, whereas the same command as a regular user is contained by permissions — the classic R1 §13 cautionary tale.
Formalize — su and sudo
Identities:
su(switch user / substitute user) spawns a shell as another user. With no argument it targetsrootand prompts for the target's password. Variants:su— switch to root but retain the original user's environment (pwdand\$USERstay where you were).su -orsu -lorsu root -— switch to root with a login environment: home becomes/root(Linux) or/(classic Unix),\$USERbecomesroot, and startup files for root are sourced. Demonstrated viapwd; echo \$USER; idcomparisons (R1 §13.1).su alice— as root, switch toalicewithout needing her password; as a regular user, you must enter her password.
sudo(superuser do) executes a single command with superuser privileges, prompting for the invoking user's password (if permitted in/etc/sudoers). It does not require the root password. Idioms:sudo command— one-off elevation (e.g.,sudo date -s ...,sudo adduser bits1).sudo su— usesudoto authenticate as yourself, thensuto become root without needing the root password — the idiom used in the live demo to gain a root shell.sudo -i/sudo -s— interactive variants.
Visual cue: shell prompt # traditionally indicates UID 0; \$ indicates regular user. id confirms: regular user uid=1000(ubuntu), after elevation uid=0(root) (course VM showed id with UID/GID and groups).
Warning from lecture: on shared educational hosts, sudo/su may fail with permission denied or user not in sudoers because privileges are not granted. That is why the demo used a local VM where the instructor controlled sudoers.
Capabilities unlocked once superuser (enumerated in session):
- Read, write, delete any file, override write-protected directories, change permissions (
chmod), group (chgrp) and owner (chown). - Create or terminate any process (
kill,psas controller). - Change any user's password without knowing the existing one (
passwd aliceas root). - Broadcast with
wall, set system clock withdate -s, limit resources withulimit, control scheduling (at,cronvia/etc/cron.allow/deny), control network services (FTP,SSHconfigs), manage hardware and service state.
This is scope, not invitation — do not attempt on unprivileged hosts.
Worked Example — privilege-gated date change (the live demo)
date
# Sun Nov 6 10:15:00 UTC 2022 (read succeeds for anyone)
date -s "2022-11-05"
# date: cannot set date: Operation not permitted (no sudo → denied)
sudo date -s "2022-11-05"
# [sudo] password for ubuntu: (you authenticate as yourself)
# Sat Nov 5 00:00:00 UTC 2022 (mutation succeeds)
date
# Sat Nov 5 00:00:00 UTC 2022
sudo date -s "2022-11-06"
# Sun Nov 6 00:00:00 UTC 2022 (restored)
Additional probes:
who
# ubuntu pts/0 2022-11-06 09:00 (192.168.1.10) ← SSH pseudo-terminal
# bits1 tty1 2022-11-06 09:05
id
# uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu),27(sudo)
id bits1
# uid=1005(bits1) gid=1005(bits1) groups=1005(bits1)
who lists logged-in users with device; id and whoami show effective identity for the current shell. Sense-check: reading date never needs privilege; writing the clock always does — the same binary, different operation, opposite permission outcome.
Assumptions & Scope
Assumption: sudo policy in /etc/sudoers permits the invoking user; su requires target password knowledge (or is bypassed via sudo su when you have sudo).
Scope: use elevation only for the task that needs it, then exit the root shell promptly. R1 §13 warns: do not work routinely as root — log in as a regular user, elevate for the specific command, then return. Prolonged root shells amplify typo damage.
Failure mode: su - changes directory to root's home, which may confuse a script that assumed the original pwd; prefer sudo command or su (without -) when you must retain the caller's working directory.
Visual intuition: graph privilege as a vertical bar: bottom 0–50% regular user (can read own files, run filters), top 50–100% superuser (can mutate any file, clock, passwords). date (read) sits at 10%; date -s (write) sits at 90% with a gate; sudo is the elevator that temporarily lifts you, su is the room you enter. The x-axis is operations, y is required privilege. Takeaway: daily practice keeps you at the bottom; you ride up only for the one operation at the top.
Pitfalls
- Trying
sudoon a shared host that does not grant it. Failure is expected policy, not a bug; use a local VM or request access.
- Confusing
suandsudopasswords.suasks for the target's (root's) password;sudoasks for yours. Entering the wrong password repeatedly locks or denies.
- Staying root after the task. Forgetting
exitleaves a#shell wherermorchmodcan damage system areas. Makewhoami/idchecks habitual.
- Using
suwithout-when environment matters. Some admin scripts depend on root'sPATH/HOME;suwithout-retains the caller's environment and may fail to find binaries or write to the wrong location. Converselysu -movespwdto/root, surprising file-relative commands.
- Over-broad
sudofor pipelines.sudo grep pattern file | sortelevates onlygrep; ifsortneeds privilege, elevate the pipeline explicitly or run a root shell.
Recap + Bridge
su switches user (full stay; su - takes full login environment), sudo borrows superuser power for one command (authenticated as yourself), and the prompt/id confirm the transition. Once superuser, you control files, processes, passwords, clock, and services — demonstrated live by gated date mutation. With privilege understood, the next section applies it to the canonical admin task: creating and inspecting users.
Real-World & Domain Connection: Every ops team lives in this model: developers use sudo systemctl restart app, data engineers use sudo mount for datasets, and instructors provision cohorts via sudo newusers (next section). The discipline — regular user by default, elevate only for the gated operation, exit immediately — is the production safety habit that prevents outages.
12.7.1 su and sudo — Acquiring Elevated Privileges
su — switch user: su without arguments attempts to become root and prompts for the target account's password; su - or su root switches with superuser environment (home, \$USER, startup). sudo — execute one command as superuser, prompting for the invoking user's password rather than root's; sudo su switches to root after a sudo authentication, the idiom used in the demo, while sudo command runs exactly that command as superuser without a persistent switch. The spoken distinction — su changes the user, sudo grants extra privileges for one command — captures practice, and the prompt change from ubuntu@... to root@... confirms transition. A warning notes that on shared educational hosts sudo/su may fail for lack of granted privileges, hence the local VM.
12.7.2 Capabilities Available to the Administrator
Once superuser, the administrator comprehensively controls the system: modify any file's contents/permissions/ownership even in write-protected directories and delete any file; create or terminate any process; change any user's password without knowing the old one; broadcast via wall; set clock/calendar with date; limit file sizes with ulimit; control scheduling services at/cron; control networking tools FTP/SSH; manage hardware, network, and service state. This enumerates scope, not an invitation on unprivileged hosts.
12.7.3 Demonstration with Date Setting and Privilege Checks
The date command illustrates a privilege-gated mutation: date shows Sun Nov 6, sudo date -s "2022-11-05" sets to Sat Nov 5, date confirms, and sudo date -s "2022-11-06" restores. Without sudo, setting the clock is denied; with sudo, it succeeds. Additional visibility includes who (users with tty/pts devices) and id (UID, GID, membership).
12.8 User Management and Bulk Creation
Creating users is the first admin workflow where sudo pays for itself — and where the choice between one-by-one and bulk creation determines whether provisioning a cohort takes an afternoon or a second.
Hook — 26 accounts, one command or 26? The lecture provisioned 26 new users whose logins start 2021.... Doing that with interactive adduser means 26 password prompts and 26 confirmation cycles. With newusers it was one file plus one command, completing in a fraction of a second. Which would you choose the night before term starts?
Intuition — artisan vs assembly line. Think of adduser/useradd as an artisan crafting one chair: measured, interactive (password, GECOS, home), good for a bespoke account. newusers is an assembly line: you lay out a parts list (a text file where each line is login:password:UID:GID:GECOS:home:shell) and the line builds all chairs at once. The artisan gives feedback per piece; the line gives speed and consistency for batches. Break point: the line is strict about format — a missing colon or field shifts all subsequent fields — whereas the artisan prompts interactively to avoid that error.
Formalize — single-user tools and the passwd structure they populate
Single-user creation:
adduser(Debian/Ubuntu family, friendlier, interactive prompts for password and metadata) anduseradd(lower-level, script-friendly, e.g.,useradd -m -s /bin/bash bits2) both create a new account. The demo used them interchangeably:sudo adduser bits1,sudo useradd bits2, each followed by setting a password (passwdinteractive, patternbits1/bits1for teaching).passwdchanges a password; as superuser you can change any account's password non-interactively and without knowing the old one.userdelremoves an account. Demo:sudo userdel bits4(no extra prompt), thensu bits4failsLogin incorrect, confirming removal. Without-r,userdelpreserves the home directory;userdel -rwould remove home and mail spool.
Four demonstrators bits1–bits4 were created individually to illustrate the interactive path.
Structure of /etc/passwd (seven colon-separated fields, T2 Ch 14 / R1 Ch 13):
- Username — login name (
bits1,root,ubuntu,SAP1,Anita) - Password field —
x(encrypted password lives in/etc/shadow, readable only by root, see R1 §13) - UID — numeric user ID
- GID — numeric primary group ID
- GECOS/comment — descriptive field, often empty or full name
- Home directory — absolute path, e.g.,
/home/bits1 - Login shell — e.g.,
/bin/bashor/usr/sbin/nologinfor non-interactive system accounts
Inspection with grep (never edit directly):
grep "^bits" /etc/passwd # all bits accounts
grep -c "^bits" /etc/passwd # count of matching users
grep "bash\$" /etc/passwd # interactive shells
grep "nologin\$" /etc/passwd # system accounts without interactive login
grep "^A" /etc/passwd # Anita
grep "^U" /etc/passwd # Ubuntu login
Auditing with ^/\$ is faster and safer than opening /etc/passwd in an editor, where a typo can lock out logins and where reading historically required elevated care.
Bulk creation with newusers:
newusers reads a text file describing many accounts and creates them in one pass, in the passwd field format. The teaching file Users (variants exist) held 26 entries prefixed 2021... (cohort identifiers), each line like:
20210001:password:UID:GID::/home/20210001:/bin/bash
# compact form: login:password:UID:GID:GECOS:home:shell
# teaching variant: 20210001:pass:1001:1001::/home/20210001:/bin/bash
Field count may be four or more colon-separated values; unspecified fields take defaults. Execution:
sudo newusers Users
Completed in a fraction of a second. Verification mirrors single-user auditing:
grep "^2021" /etc/passwd # 26 new accounts listed, each with x field, UID, shell
grep -c "^2021" /etc/passwd # 26
The note that earlier-provisioned names in the environment used the same pathway connects the exercise to visible cohort accounts, showing this is not a toy command but the actual provisioning route.
Worked Example — compare loops vs newusers (trace the cost)
Interactive loop (conceptual, not run 26 times live):
for u in 20210001 20210002 ... 20210026; do
sudo adduser \$u # prompts for password, GECOS per user → ~26× interactive steps
done
# If each adduser takes ~30s of prompts, ~13 minutes plus inconsistency risk
Bulk path (actual demo):
cat Users
# 20210001:cohort2021:1101:1101::/home/20210001:/bin/bash
# 20210002:cohort2021:1102:1102::/home/20210002:/bin/bash
# ... 26 lines
sudo newusers Users
# <1 second, no per-user prompts
grep -c "^2021" /etc/passwd
# 26
Removal check:
sudo userdel bits4
su bits4
# su: user bits4 does not exist (or Authentication failure)
ls -ld /home/bits4
# still exists because -r was not used
Sense-check: bulk creation guarantees uniform shells, homes, and password placeholders; manual loops risk typos in UID/GID or shell paths that are tedious to audit later. After bulk creation, grep "^2021.*bash\$" would confirm all 26 received /bin/bash if that was the intended shell.
Assumptions & Scope
Assumption: you have superuser via sudo/su; newusers requires it to write /etc/passwd//etc/shadow atomically.
Scope: newusers is for batch provisioning (semester start, lab onboarding, enterprise cohorts). For a single ad-hoc account, adduser's interactivity and home-creation defaults are more ergonomic.
Format caution: Users file is colon-separated, not space-separated; a missing : silently misaligns fields. Validate with awk -F: 'NF<7' or grep -c "^2021" /etc/passwd after run.
Cleanup: userdel without -r leaves home for forensic recovery; with -r it removes home and spool — choose deliberately.
Visual intuition: draw a timeline left to right: single-user path has 26 sequential boxes (adduser → passwd → mkdir home repeated), total width long; bulk path has one tall box labeled newusers Users whose height is 26 accounts but width is one command. The y-axis is accounts created, x is wall time. The horizontal line at grep -c "^2021" = 26 is the checkpoint. Takeaway: batch collapses time without changing outcome, provided the input file format is correct.
Pitfalls
- Editing
/etc/passwdby hand. Even withsudo, manualvi /etc/passwdrisks syntax errors that can lock the system. Preferadduser/useradd/newusersandgrepfor inspection.
- Confusing
adduservsuseradd.adduser(Debian) is interactive and creates home by default;useraddis lower-level and may need-mto create home and-sto set shell. Using the wrong one without flags yields accounts with missing homes orshinstead ofbash.
- Forgetting password setup.
useraddwithoutpasswdleaves an account locked; bulk file must contain a password field (or!/*to lock). The teachingbits1/bits1pattern is for demo, not production.
- Malformed bulk file. Missing colons or fields in
Userscause UID/GID/home to shift — e.g.,20210001:pass:1101may default remaining fields unexpectedly. Lint the file beforesudo newusers.
- Assuming
userdelcleans home. It does not unless-ris supplied; orphaned homes accumulate. Converselyuserdel -ras root is destructive — double-check the username.
- Not verifying after bulk. Always
grep -c "^2021" /etc/passwdand spot-checkgrep "^20210001" /etc/passwdto confirm shell/home; a silent partial failure is worse than no creation.
Recap + Bridge
Single-user tools (adduser/useradd, passwd, userdel) handle bespoke accounts; /etc/passwd's seven colon fields explain what they write; newusers scales the same format to batch speed — 26 accounts in one command, verified with grep "^2021". With users existing, the next question is collaboration: how groups and file permissions let those users share safely.
Real-World & Domain Connection: Enterprise onboarding, lab provisioning, and cloud VM fleet setup all use batch creation — HR exports a CSV, a script converts it to newusers format, and verification is grep -c "^20" /etc/passwd plus id spot checks. The same /etc/passwd with bash\$/nologin\$ auditing separates human interactive users from service accounts during security reviews.
Exam note: user creation distinctions — adduser/useradd vs newusers, primary vs secondary groups (expanded in 12.9), and userdel semantics — are conceptual comparison and scenario questions. Be ready to choose the right tool for "one bespoke account" vs "26 cohort accounts" and to trace grep "^bits" counts.
12.8.1 Creating and Removing Single Users
adduser (Debian family, interactive) and useradd (lower-level) create a new account; the demo used both (sudo adduser bits1, sudo useradd bits2), each receiving a password via passwd-style prompts (bits1/bits1 teaching pattern). passwd changes a password, and superuser can change any account non-interactively. userdel removes an account — userdel bits4 with no extra prompt, after which su bits4 fails Login incorrect; without -r the home directory is preserved. Four demonstrators bits1–bits4 were created individually.
12.8.2 Structure of /etc/passwd
Inspected with grep to avoid paging, /etc/passwd has seven colon-separated fields: (1) username, (2) field x (real encrypted password in /etc/shadow), (3) UID, (4) GID (primary group), (5) GECOS/comment, (6) home directory, (7) login shell (/bin/bash or /usr/sbin/nologin). Examples: grep "^bits" /etc/passwd lists bits1–bits4 with x, UIDs, and shell; counting via grep -c "^bits", separating interactive grep "bash\$" vs nologin\$; ^A finds Anita, ^U finds Ubuntu. Auditing with ^/\$ is faster and safer than editing the file directly.
12.8.3 Bulk Creation with newusers
Creating dozens one by one is tedious and error-prone; newusers reads a text file mirroring passwd fields and creates them in one pass. The teaching file Users contained 26 entries prefixed 2021..., each line like 20210001:password:UID:GID::/home/20210001:/bin/bash (four or more colon values: login, password, UID, GID, home, shell). Execution sudo newusers Users completes in <1s; verification grep "^2021" /etc/passwd shows 26 accounts and grep -c "^2021" is 26. This contrasts with looping adduser, saving repetition and ensuring consistency, and the provisioned names earlier in the environment used this pathway.
12.9 Groups and Permission Delegation
Users exist; collaboration requires groups. This section turns individual accounts into teams and makes a shared document writable by that team — surfacing the classic trap where group membership alone is not enough.
Hook — why did Anita's write fail? Anita was added to group bits, the file's group was changed to bits with chgrp, yet echo hello >> bits_doc as Anita was denied. Group membership was correct — id Anita showed bits — but the file's mode lacked group-write. Membership answers who the permission applies to; chmod answers whether that who may write.
Intuition — primary uniform vs club badge. Think of a primary group as the uniform you wear every day: every user is created with one, typically sharing the username (bits1 in group bits1), and files you create default to that uniform. A secondary (supplementary) group is a club badge you pin on: you keep your uniform, but the badge grants club-room access whose door is labeled with that club's name. Unless the room's door (chgrp) is labeled with the club and the lock permits club members to write (chmod g+w), the badge alone does not open it for writing. Break point: you can wear many badges, but a file has only one group label at a time; changing it to bits removes the previous group's label.
Formalize — groups, their files, and the collaboration sequence
Primary vs secondary:
- Primary group — created with the user account; every user belongs to at least one group. Files the user creates default to this primary group. Typically GID equals UID and name equals username (
bits1: x:1005:1005means userbits1with primary GID 1005, groupbits1). - Secondary (supplementary) groups — additional groups added after creation. Membership grants the group's permissions on shared resources without changing primary affiliation. Files remain owned by primary unless
chgrpornewgrpis used. Explains permission observations: even thoughamazonwas in secondary groupbits, writing failed untilchgrpandchmodwere corrected.
Structure of /etc/group (four colon-separated fields, parallels passwd):
- Group name —
AWS,bits,Anita - Password field —
x(group password rarely used) - GID — numeric group ID
- Member list — comma-separated usernames, possibly empty
Example: AWS:x:999:bits1,bits2,ubuntu means group AWS GID 999 with members bits1,bits2,ubuntu. IDs 0–499 reserved for system groups; user-defined groups should use 500 and above (lecture specified 499 cut-off, 999 as safe example; some modern systems use 1000+).
Creation:
sudo groupadd -g 999 AWS
sudo groupadd -g 1016 bits
Verification:
grep "AWS" /etc/group # AWS:x:999:...
grep "^bits" /etc/group # bits:x:1016:...
Initially member list empty before users are added.
Membership operations:
sudo adduser bits1 AWS # Debian idiom adds bits1 to supplementary group AWS
sudo adduser bits2 AWS
sudo gpasswd -a bits1 AWS # alternate explicit form (add)
sudo gpasswd -d user group # remove user from group
sudo groupdel groupname # remove group itself
After adding: grep AWS /etc/group → bits1,bits2,ubuntu; id bits1 → uid=... gid=... groups=...999(AWS) confirming supplementary membership. Manual editing of /etc/group is discouraged; use commands.
Permission triplet & the bits_doc workflow (the main lab):
Goal: users Anita, Anup, and amazon should have write access to shared file bits_doc (rendered tempfile in one run) via shared group bits.
Steps demonstrated:
- Create users (if not existing):
sudo adduser anita
sudo adduser anup
# each in primary groups anita, anup
- Create shared group:
sudo groupadd -g 1016 bits
- Add users to supplementary group:
sudo adduser anita bits
sudo adduser anup bits
sudo adduser amazon bits
- Inspect:
ls -l bits_doc
# -rw-r--r-- 1 amazon amazon ... bits_doc (group amazon before change)
- Change file's group:
sudo chgrp bits bits_doc # or chgrp bits tempfile
ls -l bits_doc
# -rw-r--r-- 1 amazon bits ... bits_doc (group now bits, but mode still r-- for group)
- Grant group write:
sudo chmod g+w bits_doc # or chmod 664
ls -l bits_doc
# -rw-rw-r-- 1 amazon bits ... bits_doc (group now rw-)
Trap: default rw-r--r-- gives read for group but not write; without chmod g+w, secondary members can only read (r--r--r-- in one demo run). The triplet is user-group-other each rwx, so after chmod g+w it becomes rw-rw-r-- allowing group write. Membership alone never grants access — the mode must consent.
Probing group membership:
grep "^bits" /etc/group # shows AWS:999 etc.
id bits1
grep "^bits" /etc/passwd # cross-check users vs groups
Worked Example — why the first attempt failed and the fix (full trace)
Initial state:
groups anita
# anita : anita (only primary before adding)
sudo adduser anita bits
groups anita
# anita : anita bits → now in bits as secondary
ls -l bits_doc
# -rw-r--r-- 1 amazon bits 0 ... bits_doc
anita tries to write:
sudo -u anita bash -c 'echo "hi" >> bits_doc'
# bash: bits_doc: Permission denied
Diagnosis: mode is rw-r--r-- → user amazon has rw-, group bits has r--, other r--. Even though anita is in bits, group permission is read-only.
Fix:
sudo chmod g+w bits_doc
ls -l bits_doc
# -rw-rw-r-- 1 amazon bits ... bits_doc
sudo -u anita bash -c 'echo "hi" >> bits_doc && echo success'
# success
cat bits_doc
# hi
Second probe: id bits1 showed membership in AWS and grep AWS /etc/group listed bits1,bits2,ubuntu, yet su amazon write test without g+w still failed — same trap. Sense-check: after chmod g+w, ls -l must show rw- in the middle triplet; if it still shows r--, the chmod did not apply (wrong file or missing sudo).
Group ID policy:
sudo groupadd -g 999 AWS # 999 >499 so allowed as user-defined, OK
sudo groupadd -g 400 mygrp # would collide with reserved 0-499 system range
Takeaway: choose GID ≥500 (lecture rule) to avoid system collision.
Assumptions & Scope
Assumption: adduser group-adding semantics (Debian) vs usermod -aG (portable) — lecture demoed adduser user group which on some distros maps to usermod; prefer gpasswd -a or usermod -aG for portability.
Scope: group collaboration scales to shared directories (set chmod g+s for setgid, not shown but natural extension) and to service groups (docker, sudo). The pattern chgrp + chmod g+w is the minimal team-write recipe.
When it breaks: file system mounted with restrictive acl or umask 007 may override; NFS may squash root and map groups via idmap.
Visual intuition: draw a Venn of users Anita, Anup, amazon overlapping in circle bits. Draw file bits_doc with a luggage tag labeled group: bits and a three-slot lock rwx | rwx | rwx. Before fix: tag says bits but lock's middle slot is r-- (read only). After chmod g+w: middle slot flips to rw-, overlap members now open the middle lock. X-axis is membership, Y is permission bits; takeaway: both dimensions must align for write.
Pitfalls
- Membership without mode. Adding to
bitsand runningchgrpis insufficient; withoutwbit for group, write is denied. Mustchmod g+w.
- Thinking
chgrpchanges primary group. It changes the file's group, not the user's primary. User's new files still default to primary unlessnewgrpis used.
- Manual editing of
/etc/group. Directvirisks comma misplacement or duplicate GID; usegroupadd/gpasswd.
- GID collision. Using
<500for user groups collides with system groups; lecture mandates≥500(example999,1016).
- Forgetting re-login or
newgrp. Group membership for an existing shell may not refresh until re-login ornewgrp bits;idmay show new groups but current shell's effective groups may lag.
- Confusing file name variants.
bits_docvstempfilein the session are the same role: the shared document. Apply logic to the name at hand.
- Assuming one group per user. Every user has primary plus potentially many secondaries;
idlists all,groupssummarizes.
Recap + Bridge
Primary = default uniform (one per user, owns new files); secondary = club badges (bits, AWS) that grant shared access only when the file's group is set via chgrp and its mode permits write via chmod g+w (rw-rw-r--). GIDs ≥500 avoid system collision; membership is verified with id/grep /etc/group. With sharing solved, the final operational skill is session awareness — who is logged in where, and how to reach them.
Real-World & Domain Connection: Team directories on shared servers, CI artifact folders, and lab submission drop-boxes all use this pattern: groupadd devs, gpasswd -a alice devs, chgrp devs /srv/shared, chmod 2775 /srv/shared (setgid so new files inherit devs). Auditing with grep team /etc/group plus ls -l checks is the routine access-review loop before releases.
12.9.1 Primary and Secondary Groups
Linux distinguishes two associations: Primary group — created with the user, every user belongs to at least one, typically sharing the username (bits1 in bits1), and new files default to it. Secondary (supplementary) groups — additional groups added after creation; membership grants that group's permissions on shared resources without changing primary affiliation, and files remain owned by primary unless chgrp/newgrp is used. This explains write failures despite membership: the effective file group was not the secondary until explicitly changed.
12.9.2 Structure of /etc/group and Group Creation
/etc/group parallels passwd with four colon fields: (1) group name (AWS, bits, Anita), (2) field x, (3) GID, (4) comma-separated member list. Example AWS:x:999:bits1,bits2,ubuntu with GID 999. IDs 0–499 reserved for system groups; user-defined groups should use ≥500 (lecture cutoff 499, safe example 999). Creation via sudo groupadd -g 999 AWS, groupadd -g 1016 bits; verification grep "AWS" /etc/group, grep "^bits" /etc/group initially shows empty member list.
12.9.3 Adding Users to Groups and Managing Membership
Membership shown as sudo adduser bits1 AWS (supplementary), adduser bits2 AWS, alternate gpasswd -a bits1 AWS, removal gpasswd -d user group, and groupdel groupname to remove group. After adding, grep AWS /etc/group shows bits1,bits2,ubuntu and id bits1 reflects supplementary group. Probes via grep passwd/group and id per user; manual file editing discouraged.
12.9.4 The bits Document Task, chgrp, and Write Access
Goal: Anita, Anup (and Amazon in interactive attempt) should write to bits_doc/tempfile via shared group bits. Steps: 1) sudo adduser anita, adduser anup (each in own primary), 2) sudo groupadd -g 1016 bits, 3) sudo adduser anita bits, anup bits, amazon bits, 4) ls -l bits_doc shows owner/group/permissions (before change group amazon), 5) sudo chgrp bits bits_doc, 6) chmod g+w bits_doc. Trap: after chgrp, ls -l showed r-- for group and amazon write denied; default rw-r--r-- gives group read not write, so secondary members could only read; permission triplet rwx for user-group-other means rw-rw-r-- after chmod allows group write. Membership alone insufficient — mode must grant it.
Q: If I add Anita to group bits and run chgrp bits bits_doc, why can she still not write? A: Membership makes Anita a principal for the file's group bits, but the permission bits may still be r-- for group. Membership selects which rwx triplet applies; the w bit itself must be present. chmod g+w bits_doc (or mode 664/660 that includes group write) is required before secondary members gain write.
Q: Is the bits group attempt working for bits1? A: id bits1 shows bits1 is a member and grep AWS /etc/group confirms members, but file-level ls -l and su amazon write attempts without group-write demonstrate the missing w bit on the shared file — the demonstration paused to discuss permission triples (rwx for user, group, other) before retrying with chmod g+w.
Teaching moment preserved
Warning — group membership alone insufficient without group-write bit: The lecture deliberately staged a failing write after correct chgrp to force the realization that ACL is two-factor: who you are (group) × what the file allows (mode). The correction — adding w for group — is the durable lesson, not an incidental permission tweak.
12.10 Session Awareness, Communication, and Workspaces
Administration ends with awareness: who is on the system, where they are attached, how to reach them, and how the system multiplexes simultaneous logins.
Hook — five logins, one human. who on the demo machine showed ubuntu on pts/0, plus bits1 on tty1, bits2 on tty2, bits3 on tty3, bits4 on tty5, and even bits5 and tty7 graphical. One physical machine, six simultaneous sessions. How does Linux keep them separate, and why does your SSH session say pts while the local console says tty?
Intuition — rooms vs phone extensions. Think of tty (teletype) devices tty1–tty6 as physical rooms in a building — you walk to the room (Ctrl+Alt+F1) and log in at its door. pts (pseudo-terminal slave) devices pts/0, pts/1 are phone extensions — remote SSH callers dial in and get an extension without occupying a physical room. who is the receptionist's board listing who is in which room or on which extension and since when. wall is the PA system that broadcasts to every room and extension at once. Switching virtual consoles is walking between rooms; your SSH pts call stays connected regardless of which room you stand in — until the network drops. Break point: tty persists locally even if the network hiccups; pts is tied to the network and may drop if ifconfig IP changes or SSH disconnects, which the demo experienced and recovered from by staying on local tty consoles.
Formalize — who, tty/pts, wall, and virtual consoles
who — session census: Lists each logged-in user, device, and login time. Example from demo:
ubuntu tty7 2022-11-06 09:00 (:0) ← graphical desktop (see below)
bits1 tty1 2022-11-06 09:05
bits2 tty2 2022-11-06 09:06
bits3 tty3 2022-11-06 09:07
bits4 tty5 2022-11-06 09:08
bits5 tty? ...
ubuntu pts/0 2022-11-06 09:00 (192.168.1.10) ← SSH from instructor laptop
pts/0 field in parentheses shows the remote origin for network logins.
tty vs pts:
tty1–tty6— local virtual consoles tied to the machine's keyboard/display. Each is an independent kernel terminal device (/dev/tty1etc.).pts/*— pseudo-terminal slave devices for remote logins (SSH,telnet, terminal emulators). EachSSHconnection allocates a newptsnumber; the instructor's VM connection appeared aspts/0orpts/1distinct fromttyentries.- Auxiliary probes:
whoamiprints effective user for current shell,idprints UID/GID/groups,tty(no args) prints the device of the current shell (/dev/pts/0when on SSH) — handy to know which line you are on before broadcasting.
wall — write to all: Broadcasts a message to every logged-in terminal immediately, without a recipient list. Session demo:
wall
Hello everyone. System shutdown in 5 minutes. Save your work!
# Ctrl-D to send EOF
After Enter/Ctrl-D, the banner:
Broadcast Message from ubuntu@vm (pts/0) at 10:20 ...
Hello everyone system shutdown in 5 minutes. Save your work!
appears inline on tty1, tty2, tty3, and the originating pts, interleaved with each recipient's current session. wall requires no who parsing; it delivers to all who entries by design. Historically wall needs superuser or mesg y permission on terminals; modern wall may be setgid tty.
Linux virtual consoles and the graphical session:
Ctrl+Alt+F1throughCtrl+Alt+F6switch to virtual consolestty1–tty6, each presenting a textlogin:prompt. Demo loggedbits1onF1,bits2onF2,bits3onF3,bits4onF4, confirmed viawho.Ctrl+Alt+F7(on many distrosF1/F2is graphical; in this VMF7was desktop) returns to the graphical desktop, reported astty7inwho.- Network hiccup handling: a lost
ifconfigIP after a service hiccup dropped theptsSSH session, but localttysessions persisted; the instructor stayed onttyconsoles and retriedifconfig/service networking restart, illustrating the resilience split.
Supplementary commands reachable from any virtual console: exit leaves a console, clear refreshes display, passwd changes password, ulimit shows/limits per-user resources (ulimit -f max file size), all without affecting parallel sessions.
Process lineage note (R1 Ch 13): each tty's getty → login → shell chain is respawned by init per /etc/inittab respawn lines, so logging out returns to login: on that tty without affecting other tty/pts sessions.
Worked Example — mapping who to devices and broadcasting
Step 1 — populate consoles:
# From graphical terminal (tty7), switch: Ctrl+Alt+F1, login bits1
# Ctrl+Alt+F2, login bits2
# Ctrl+Alt+F3, login bits3
# Ctrl+Alt+F7 back to desktop
who
# bits1 tty1 ...
# bits2 tty2 ...
# bits3 tty3 ...
# ubuntu pts/0 ... (your SSH)
# ubuntu tty7 ... (graphical)
tty
# /dev/pts/0 ← current shell is SSH pseudo-terminal
Step 2 — broadcast:
wall <<'MSG'
Hello everyone. System shutdown in 5 minutes. Save your work!
MSG
# Observe on tty1: Broadcast Message from ubuntu@vm (pts/0) ...
# Same on tty2, tty3, pts/0
Step 3 — verify after broadcast:
who -a # -a shows all, with idle and pid
who am i # owner of current terminal
id # confirms uid/gid/groups for privilege context
Step 4 — network resilience:
ifconfig eth0 down # simulated hiccup → pts/0 may freeze/disconnect
# Local tty1–tty3 remain responsive; re-enable with `sudo ifup eth0` from tty1
Sense-check: who after wall still lists all sessions; wall does not log anyone out, it only writes. To actually schedule shutdown, sudo shutdown -h +5 "Save work" would both broadcast and power down after 5 minutes.
Assumptions & Scope
Assumption: traditional SysV tty1–tty6 + tty7 desktop mapping applies to the demo VM; modern systemd systems use logind and may place graphical on tty1/tty2 and text on tty3–tty6 — check who and systemctl get-default.
Scope: wall is for urgent notices to interactive users; for daemon or non-interactive sessions use mail, logger, or shutdown's own wall. pts numbering is dynamic — pts/0 today may be pts/3 after reconnect.
Failure mode: mesg n on a terminal blocks wall/write to that terminal; users may have disabled messages. wall may require sudo or group tty membership depending on distribution.
Visual intuition: picture a building floor plan: six rooms labeled tty1–tty6 along a corridor, one executive suite tty7 (desktop), and a phone switchboard with extensions pts/0–pts/N for remote callers. who is a roster board at reception with pins for each occupant. wall is a loudspeaker icon with arrows to every room and extension. The x-axis is device, y is user; takeaway: sessions multiplex in space (room vs extension), not by disconnecting others.
Pitfalls
- Confusing
ttyandpts.tty1is local console;pts/0is your remote SSH — they are different devices with different persistence. Diagnosing "who is logged in where" requires reading the second column ofwho, not just the name.
- Expecting
SSHto survive network loss liketty. A localttysurvives;ptsis network-bound and drops if IP changes (ifconfigdemo). Have a local console fallback.
- Forgetting to switch back to graphical. Staying on
tty1text console and thinking the desktop is frozen;Ctrl+Alt+F7(orF1on newer) returns to GUI.
- Broadcast without purpose.
wallinterrupts every user; do not use for chat — usewrite user ttyto message one user/terminal, ormailfor non-urgent.
- Misreading
who'stty7. On this VMF7is graphical, but on your laptop it may betty1ortty2; always verify withwhorather than assuming.
Recap + Bridge
who shows who is where (tty local rooms vs pts remote extensions), wall PA-broadcasts to all, and Ctrl+Alt+F1–F6/F7 multiplex independent logins plus a graphical desktop on one machine. Together with grep, privilege, users and groups, you now have the full loop: find text, manage who may see or change it, and reach those who are logged in.
Real-World & Domain Connection: In data-center ops, who/w plus last audits active and historic sessions; wall/shutdown warns before patch reboots; tty/pts diagnosis explains why SSH idle disconnects yet the console process continues; and who with id/grep pipelines (who | grep pts) separates remote from local risk during incident response.
12.10.1 who, tty, and pts — Local versus Remote Sessions
Linux tracks attachment: who reports each logged-in user, device, and login time — e.g., ubuntu and bits1–bits4 on tty1–tty5 plus ubuntu on pts/0/pts/1 via SSH. tty devices (tty1–tty6) are local virtual consoles on the machine's keyboard/display; pts (pseudo-terminal slave) devices are remote logins such as the SSH connection from the instructor's laptop, appearing as pts/... distinct from tty. id and whoami complement who by showing effective user and group for the current shell.
12.10.2 Broadcasting with wall
wall — write to all — broadcasts immediately to every logged-in terminal, demoed as:
wall
Hello everyone. System shutdown in 5 minutes. Save your work!
# Ctrl-D
After execution, Hello everyone system shutdown in 5 minutes. Save your work! appeared on tty1, tty2, tty3, and the originating terminal, bannered inline. It requires no recipient list; it delivers to all who entries by design.
12.10.3 Linux Virtual Consoles and the Graphical Session
A Linux host offers multiple simultaneous logins: Ctrl+Alt+F1–F6 switch to virtual consoles tty1–tty6 with text login prompts (demo logged bits1 on F1, bits2 on F2, bits3 on F3, bits4 on F4, who confirmed), and Ctrl+Alt+F7 (on some distros F1/F2 is graphical; in this VM F7 was desktop) returns to the graphical session reported as tty7 in who. This explains why who shows one human on several devices — each function-key console is an independent login. Network hiccups such as a lost ifconfig IP after a service hiccup were handled by persisting on local tty consoles and retrying network restart, illustrating that tty sessions persist while pts SSH sessions may drop if the network changes. Supplementary commands exit, clear, passwd, ulimit remain reachable from any virtual console.
Exam Guidance Summary
This section consolidates the examinable decisions and prediction skills emphasized across the lecture — the fine-grained distinctions that map directly to short-answer and output-prediction questions.
- Assignment and team sizing (12.1): Three members per group is the design target and the evaluation assumption. Workload division, program allocation freezing, and preparation time all assume a trio. Smaller groups (at most one group of two permitted) must negotiate to reach three; delayed formation directly reduces time for the command-heavy scripts that follow. Expect program-allocation timing and team-formation rationale as short-answer prompts.
- Shell programming through commands (12.1–12.2, 12.8–12.9): Shell scripting is assessed via purposeful use of system commands inside scripts, not isolated pattern printing. Be prepared to embed command results (
grepcounts,idoutput,/etc/passwdprobes) inside loops/conditionals, and to justify why a particular command or option (grep -cvsgrep -o | wc -l,adduservsnewusers) fits the file-processing step. Illustrative vs assessed tasks are a common conceptual contrast.
- grep reporting options (12.3): The distinctions between
-c(count lines, not words),-l(list file names only) vs default lines vs-h(suppress names) vs-o(only matching substring), and-w(whole word) vs substring vs-i(case-fold) vs-v(invert) are directly testable. Practice how-i,-v,-ncompose and which flag dominates output shape (e.g.,grep -i -v -cvsgrep -c). The table-document andgrep_filecounts (3 → 5 with-i, 4 → 2 inverted with-i) are prototypical output-prediction exercises.
- Regular-expression mechanics (12.4–12.6): Be ready to trace a given pattern on a provided file and explain why a variant differs:
.*vs*—.*bridges spaces including empty;*repeats only the preceding atom (this*filefails to bridge space,this.*filesucceeds).\.vs.— literal dot vs wildcard (so5.≠5\.≠5\..).^outside vs^inside[^...]— anchor (beginning of line) vs negation (not in set), e.g.,^[0-9](line starts digit, matches nothing intable.doc) vs[^0-9](non-digit, matches all lines).- Character classes
[A-Z],[A-Za-z]*, shorthands\d/\D/\w/\W/\s, and consecutive atoms[A-Z][A-Z][A-Z]controlling required length. - Escaping for literal
\.when grepping decimals, IPs, versions.
- Administrative distinctions (12.7–12.10): Conceptual comparisons and scenario tasks are frequent:
su(switch user, needs target password,su -takes login environment) vssudo(one command as superuser, needs invoker password,sudo suidiom).adduser/useradd(one bespoke account, interactive vs need-m/-s) vsnewusers(batch of 26 from colon-separated file, sub-second) vsuserdel(-rnuance, home preservation)./etc/passwdseven fields andbash\$vsnologin\$interactive audit,/etc/groupfour fields and GID ≥500 rule.- Primary (default file group, one per user) vs secondary (supplementary, many) and the two-step sharing
chgrp bits bits_doc+chmod g+wwhere membership alone is insufficient — theAnita/bits_docscenario. wallbroadcast semantics (allwhoentries, no recipient list) vswriteto a single terminal.whodevice reading:tty1–tty6local virtual consoles (Ctrl+Alt+F1–F6) vspts/0SSHpseudo-terminals vstty7graphical (Ctrl+Alt+F7on this VM) and whyptsdrops on network hiccup whilettypersists.
- Study advice: For each filter or regex problem, write the pattern atom by atom, state what each atom consumes or asserts, then simulate it line by line on the given file content — especially noting line-start/end and literal-dot adjacencies. For admin scenarios, draw the two-axis check: group membership (who) × file mode (rwx) — both must align.
Key Industry Applications
grepas triage for large text datasets (12.2–12.6): In production,grepis the first filter for log forensics (grep -i ERROR app.log | grep -v -i timeout), config auditing (grep "^PermitRootLogin" /etc/ssh/sshd_config,grep "^bits" /etc/passwd,grep "bash\$" /etc/passwdvsgrep "nologin\$"to separate interactive from system accounts), and pipeline shaping (ps aux | grep apache,ls | grep -v temp,cat mail | grep "^From"). Literal-dot escaping (grep "192\.168\." auth.logfor local IPs,grep "5\." data.csvfor decimals,grep "1\.2\." CHANGELOGfor version strings) prevents wildcard over-matching where a dot must be literal, and anchors^/\$validate line-oriented formats (e.g.,grep "^ERROR:.*\$"). Combined withgrep -c/-l/-oand downstreamsort | uniq -c | awk, it turns thousands of lines into actionable counts before heavier tools are invoked.
- System administration with superuser delegation (12.7): The
su/sudomodel governs all privileged operations in operations teams — restarting services (sudo systemctl restart nginx), mounting datasets (sudo mount), and changing clocks or passwords. The discipline taught (regular user by default,sudoone command at a time,exitpromptly, verify withid/whoami) is the production safety habit that preventsrm -rfcatastrophes noted in administrative texts. Auditing withwho/id/grepon/etc/passwdand/etc/groupforms the basic access-review loop for compliance.
- Batch user and group provisioning for team access (12.8–12.9): Semester-start cohort creation (
newusersfrom an HR export of 262021...accounts in onesudo newusers Usersrun, verified withgrep -c "^2021" /etc/passwd) is the standard alternative to error-proneadduserloops, and the same pattern scales to enterprise onboarding and lab fleet setup. Managing groups (groupadd -g 1016 bits,gpasswd -a anita bits,chgrp bits /srv/shared,chmod g+w/chmod 2775with setgid so new files inherit the shared group) implements team-based access for shared directories, CI artifacts, and submission drop-boxes. TheAnita/bits_doctrap — membership withoutg+wis read-only — is the canonical lesson that group membership (who) must be paired with file mode (what) and verified vials -landid.
- Session and communication awareness (12.10): Interpreting
who(tty1–tty6local virtual consoles onCtrl+Alt+F1–F6vspts/0remoteSSHpseudo-terminals vstty7graphical) lets on-call engineers know whether a suspected session is local or remote during incident response (who | grep ptsto isolateSSHusers). Broadcasting urgent notices withwallbefore maintenance (wall <<'MSG' System shutdown in 5 minutes ...) remains the quickest in-band warning to all interactive sessions beforeshutdown. Understanding that localttysessions persist whileptsSSH sessions drop on network/IP changes explains why console-based recovery (Ctrl+Alt+F1) is the fallback when remote access fails, and howinitrespawnsgetty/login/shellper/etc/inittabkeeps other consoles alive.
- Glue-role synthesis: The lecture's overarching message — shell scripts are practical when they orchestrate filters like
grepfor meaningful administration — is the daily reality of platform engineering: a five-line script thatgreps logs for error signatures, counts with-c, andmails orwalls a report replaces hours of manual inspection, and the same^/\$/\.pattern skills transfer unchanged to validating data files, auditing accounts, and gating automated pipelines.
SP Lecture 12 notes · Shell Filters and System Administration
Sections Breakdown
Shell scripts glue commands with loops/conditionals; assignment expects practical file and admin automation for teams of three, not pattern printing.
grep is a selective filter (g/RE/p) that scans lines for a literal or regex pattern and prints matches; syntax grep [options] pattern [file ...] with exit codes 0/1/2.
Options reshape grep reporting: -c counts lines, -l lists files, -o isolates matches, -h/-n control labels, -i/-w/-v control match strictness, -F/-E/-f choose pattern language.
Atoms: . one any, * zero-or-more of previous (so .* any string), [...] one of set with ranges; star vs dot-star is the key trap; classes control length.
Anchors ^/$ assert line edges zero-width; \ literalizes (. -> \.); -w enforces whole-word; -E/-F choose extended vs fixed; ^ placement outside vs inside [] flips anchor vs negation.
Hands-on tracing on grep_file/demo_file and table.doc: counts, anchors, literal dots, -w, and Q&A on star vs dot-star, dot-dot analogy, caret placement.
su switches user (su - takes login env), sudo borrows superuser for one command; prompt and id confirm; gated demo date -s; superuser scope covers files, processes, passwords, clock, services.
adduser/useradd for one account, /etc/passwd seven fields, newusers bulk 26 accounts from colon file in one command, verified with grep ^2021.
Primary = default uniform, secondary = club badges; /etc/group 4 fields, GID >=500; gpasswd/adduser manage; sharing needs chgrp bits + chmod g+w; membership without w stays read-only.
who lists tty (local rooms tty1-6) vs pts (SSH extensions), wall PA broadcasts to all, Ctrl+Alt+F1-6 virtual consoles and F7 graphical multiplex sessions; local tty persists when pts drops on network hiccup.
Consolidated exam focus: trio team sizing, command-driven scripting, grep option and regex tracing, admin distinctions primary/secondary, chgrp+chmod, wall/tty/pts.
grep triage, superuser ops, batch provisioning and group sharing, session awareness as production patterns.
Exam Revision Notes
Below is the distilled, exam-ready core. Every entry comes from the full explanation above. Use this section for rapid review; return to the main notes when a point needs more context.
Shell Scripts and Assignment Structure
Must-know: Scripts are assessed on purposeful command use inside loops, not star patterns; teams of three, one group may have two.
Top pitfall: Mistaking star-pattern illustration for the assessed objective; learning scripting without command fluency.
Self-check: Why does fluency on the command line transfer directly into scripts?
Connects to: 12.2, 12.3
The grep Filter — Purpose and Syntax
Must-know: grep selects lines containing pattern without modifying files; pattern may be literal or regex; exit 0 found, 1 not found, 2 file error.
grep [options] pattern [file ...]
Top pitfall: Forgetting quotes on patterns with spaces/shell metas; expecting in-place edit; directory without -r gives Is a directory.
Self-check: What exit status does grep return when the pattern is not found vs file not found?
Connects to: 12.3, 12.4
grep Options for Output Control
Must-know: -c counts lines not words; -l lists filenames; -w whole word vs substring; -i folds case; -v inverts; they compose.
grep -c/-l/-o/-h/-n/-i/-w/-v/-e/-F/-f/-E pattern [file]
Top pitfall: Confusing -c line count with occurrence count; expecting -l to show lines; -i inflating matches; -w substring surprise.
Self-check: If grep this finds 3 lines, what do grep -c this, grep -i -v -c this, and grep -o this | wc -l each report and why?
Connects to: 12.4, 12.5
Regular Expression Building Blocks
Must-know: . one any; * repeats preceding atom; .* bridges spaces; [A-Z] one capital; [A-Z]* zero-or-more; need [A-Za-z][A-Za-z]* for one-or-more.
Top pitfall: Reading * as any string; forgetting .* matches empty; confusing single char class with string.
Self-check: Why does this*file not bridge a space while this.*file does?
Connects to: 12.5, 12.6
Anchors, Escaping, and Word Matching
Must-know: ^ outside anchors start, ^ inside leading [^...] negates; $ anchors end; \. literal dot; -w whole word; -E adds +?|().
^SAP , bash$, 5\. , 5\.., grep -w North, grep -E pattern
Top pitfall: ^[0-9] vs [^0-9] confusion; 5. vs 5\. vs 5\..; basic vs extended +|() surprise.
Self-check: Trace ^[0-9] vs [^0-9] on table.doc — which prints nothing, which prints all, and why?
Connects to: 12.6, 12.8
Worked grep Examples — File Searches and Table Document
Must-know: Trace counts 3 vs 5 with -i; ^this vs file$ vs file\. vs ^this.*file\.$; 5\.. hits column four not bare 5; -w excludes Northwest.
grep -i -c this; grep ^this.*file\.$; grep 5\.. ; grep -w North ; grep ^[0-9] vs [^0-9]
Top pitfall: Counting lines vs occurrences; star vs dot-star; dot-dot as parent dir; caret outside vs inside; trailing dot in file$ vs file\.
Self-check: Why does grep -w 5\. on table.doc yield no output while grep 5\. matches lines?
Connects to: 12.5, 12.7
Superuser Status and Privileged Operations
Must-know: su needs target password, sudo needs invoker password; su - changes HOME/USER; id uid 0 = root; date -s gated; read vs write privilege.
su ; su - ; sudo command ; sudo su ; date -s 2022-11-05
Top pitfall: Trying sudo on unganted host; confusing passwords; staying root and damaging system; su without - retaining wrong env.
Self-check: What prompts differ between su and sudo and what does id show after each?
Connects to: 12.8, 12.9
User Management and Bulk Creation
Must-know: /etc/passwd 7 fields (user:x:UID:GID:GECOS:home:shell); adduser interactive vs useradd needs -m -s; newusers Users bulk; userdel -r nuance.
sudo adduser bits1 ; grep ^bits /etc/passwd ; sudo newusers Users ; grep -c ^2021 /etc/passwd
Top pitfall: Editing /etc/passwd by hand; forgetting -m/-s on useradd; malformed colon file; assuming userdel cleans home.
Self-check: When would you choose newusers over adduser and how do you verify 26 accounts were created?
Connects to: 12.9, 12.5
Groups and Permission Delegation
Must-know: Primary one per user, default file group; secondary many; /etc/group 4 fields; groupadd GID>=500; sharing = chgrp + chmod g+w; ls -l shows rwx triplet.
sudo groupadd -g 1016 bits ; sudo gpasswd -a anita bits ; sudo chgrp bits bits_doc ; sudo chmod g+w bits_doc
Top pitfall: Membership without g+w still denied; chgrp does not change user primary; manual /etc/group edit; forgetting re-login for new groups.
Self-check: Why does Anita added to bits still get Permission denied on bits_doc after chgrp, and what chmod fixes it?
Connects to: 12.8, 12.10
Session Awareness, Communication, and Workspaces
Must-know: tty1-6 local consoles vs pts SSH slaves; who second column shows device; wall broadcasts to all; Ctrl+Alt+F7 returns to desktop; pts drops on network loss.
who ; wall ; Ctrl+Alt+F1-6 / F7
Top pitfall: Confusing tty vs pts; expecting SSH to survive network like tty; thinking desktop frozen when on tty1.
Self-check: In who output, how do you distinguish a local console login from an SSH login and what broadcast reaches both?
Connects to: 12.7, 12.8
Exam Guidance Summary
Must-know: Trace grep patterns atom by atom on given file; two-axis check membership x mode.
Top pitfall:
Self-check:
Connects to: -
Was this lecture useful?
BitsNotes AI Assistant
Subject Notes AssistantConfigure AI Chat
Choose how to access the chatbotSigned in as
Powered by BitsNotes — 20 messages per day. No API key needed. Want unlimited access? Use "Bring Your Own Key" mode.
Sign in to use AI Chat
Get 20 free AI messages per day to ask questions about your lecture notes. Sign in with Google or GitHub — it takes 5 seconds.
Sign In to BitsNotesSwitch to "Bring Your Own Key" tab above for unlimited access with any OpenAI-compatible provider.