Text Processing with sed and tr

Context: FIT2014_MOC · Lab 0 Linux tooling · the applied face of Regular Expressionssed/grep patterns are regular expressions (POSIX BRE) · extends Shell Toolkit (Cheatsheet) Problem it solves: transform or search text line-by-line by a pattern — substitute, delete, translate, or match.

Quick Revision

  • 🎯 Trigger: “replace/delete/translate/match text by a pattern” ➔ sed (substitute), tr (char-by-char map), grep (search). The patterns are regular expressions.
  • ⚡ Key Constraint: sed/grep use POSIX BRE, where grouping and repetition are backslash-escaped\(...\), \{...\} — the opposite of the theory notation. And s/// replaces only the first match per line unless you add g.

🔧 sed — substitute by regex

sed 's/pattern/replacement/flags' file — for each line, replace pattern with replacement.

sed 's/A Lady/Jane Austen/' file    # first match per line
sed 's/A Lady/Jane Austen/g' file   # g = every match on the line
echo "0001" | sed 's/001/10/'       # -> 010 (leftmost match only)
  • Output only ➔ result goes to stdout; the file is unchanged (redirect with > to save).
  • Special chars in patterns\t tab, \n newline, \/ a literal slash (since / delimits the script).

🎯 Character classes & anchors (POSIX BRE)

PatternMatchesExample
[aeiou]any one listed charb[aeiou]t → bat/bet/bit/bot/but
[a-z]a range (by ASCII order)[N-Z] upper half; [0-9] a digit
[^aeiou]any char not listed (^ first)[^a-zA-Z] a non-letter
^patline starts with patanchor at start
pat$line ends with patanchor at end
^pat$whole line is patboth anchors

🔁 Subpatterns & backreferences

Wrap part of the pattern in \(...\); reuse the captured text as \1 (up to \9, left-to-right) in the replacement.

# fix NSW postcodes (2xxx) to Victorian (3xxx), keeping the last 3 digits:
sed 's/2\([0-9][0-9][0-9]\)/3\1/' file      # 2xxx -> 3xxx
# swap a single-digit fraction  a / b  ->  b / a :
sed 's/ \([0-9]\)\/\([0-9]\) / \2\/\1 /' file
  • \1 = the first \(...\) ➔ counted by opening paren, left to right.

🔤 tr — translate characters

tr string1 string2 maps each char in string1 (the domain) to the char at the same position in string2.

echo "abracadabra" | tr abc 123      # -> 12r131d12r1  (a->1, b->2, c->3)
tr 'A-Z' 'a-z'                        # uppercase -> lowercase
tr -d 'aeiou'                        # -d: DELETE listed chars (no string2)
tr -s ' '                            # -s: SQUEEZE runs of a char to one
  • No file argstr reads stdin, writes stdout; use redirection/pipes for files.

✍️ Practice (write from blank)

⚠️ Common Mistakes

  • 💡 BRE escaping is inverted ➔ in sed/grep BRE, (, ), {, } are literal; grouping/repetition need \(, \), \{, \}. (The theory’s , use bare metacharacters — see Regular Expressions.)
  • 💡 s/// is first-match-only ➔ add the g flag for all matches on a line; forgetting g silently leaves later matches untouched.
  • 💡 Ranges are ASCII, not alphabetic-only[A-z] accidentally includes [, \, ], ^, _, backtick; use [A-Za-z].
  • 💡 These tools stream to stdout ➔ they never edit the file in place here; capture with > out (⚠ overwrites) or a pipe.
  • 💡 tr maps single characters, not stringstr abc xyz is a per-character map (a→x, b→y, c→z), not a word substitution — for word replacement use sed.

🧠 Active Recall