Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.
sed

Solving the FizzBuzz problem with GNU sed
Release Status Maintained
Last Release 4.9 (2022-11-07)
Language(s) C
Developer(s) GNU sed: GNU Project, et al.
Website https://www.gnu.org/software/sed/

sed (Stream EDitor) is a powerful text processing tool available in Unix-like operating systems, used for filtering and transforming text, especially when working with streams of text data. Most commonly, it is ‘used for extracting part of a file using pattern matching or substituting multiple occurrences of a string within a file.’[1]

History

sed dates back to the early 1970s at Bell Labs. It was developed from 1973 to 1974 by Lee E. McMahon as a Unix utility designed to parse and transform text using a simple programming language.[2] It was based on the scripting features of the earlier interactive editor ed (1971) and the even earlier qed (1965–66), inheriting their pattern matching and substitution syntax, notably the use of slashes for patterns and the s/// substitution command.[3]

sed first appeared in Version 7 Unix and was created to serve as a general-purpose line-oriented stream editor, evolving naturally as a successor to the grep command. While grep was used for searching text with regular expressions, sed was designed to perform substitutions and other editing operations on streams of text, making it more versatile for text processing tasks.[4] The name sed reflects its function as a stream editor, capable of performing global regular expression substitutions and deletions.

sed was one of the earliest tools to support regular expressions and influenced many later languages, including AWK and Perl. AWK, developed later, and sed together, functioned as complementary tools for text processing in Unix shell scripts. Both sed and awk inspired Perl's design, especially in its pattern matching and substitution features.[3]

Over time, several variants of sed have emerged. GNU sed added features like in-place file editing, while other versions like ssed (super-sed) extended regular expression compatibility to Perl-like syntax.[5] A minimal version called minised was reverse-engineered from BSD sed and used in embedded systems for its speed and low memory usage.[3]

Syntax

The general syntax in sed is:

<address#1>{<command#1>; <command#2>; ...}

While at least 1 command is needed, addresses are optional; specifying no commands does not alter the text stream in most cases. If a filter corresponds to only 1 command, the braces can be omitted:

<address#1><command#1>

To specify multiple commands, separate them with new lines. Most commands also allow separation by semicolons (;), but greedy commands such as c and i take in the semicolons and the rest of the line, and thus cannot be separated with semicolons.

Commands

  • s/<regex>/<replacement>/<flags> performs substitution. The g flag replaces all matches per line; without it, only the first match is replaced. Other flags: \1,\2,... (The n-th regex group), p (print on replace), i (case-insensitive), w <file> (write to file).
    • e.g.: sed 's/red/blue/g' replaces all “red” with “blue” (including in “Fred” → “Fblue”).
    • e.g.: sed 's:\bdog\b:cat:g' replaces whole words “dog” with “cat”.
  • d deletes the current pattern space. Often used with addresses.
    • e.g.: sed '/error/d' deletes lines containing “error”.
    • e.g.: sed '3,7d' deletes lines 3 to 7.
  • p prints the current pattern space. Usually combined with -n to suppress automatic printing.
    • e.g.: sed -n '/important/p' prints only lines containing “important”.
  • a <text> appends <text> after the current line. Text continues until a newline not escaped with \.
    • e.g.: sed '3a\New Line' appends “New Line” after line 3. This is the same as sed '3a New Line'
  • i <text> inserts <text> before the current line.
    • e.g.: sed '1i\Header' inserts “Header” before line 1.
  • c <text> changes the current line to <text>.
    • e.g.: sed '/old/c\new content' replaces lines matching “old” with “new content”.
  • y/<src-chars>/<dest-chars>/ transliterates characters one-to-one (like tr).
    • e.g.: sed 'y/abc/ABC/' converts ‘a’→‘A’, ‘b’→‘B’, ‘c’→‘C’.
  • q [<exit-code>] quits processing immediately. With address, exits after processing that line.
    • e.g.: sed '5q' processes only the first 5 lines.
  • r <file> reads a file and appends its content after the current line.
    • e.g.: sed '/End/r data.txt' inserts contents of “data.txt” after lines containing “End”.
  • w <file> writes the current pattern space to <file>.
    • e.g.: sed '/important/w log.txt' saves lines with “important” to “log.txt”.
  • = prints the current line number to stdout.
    • e.g.: sed -n '/pattern/=' prints line numbers containing “pattern”.
  • n next line: replaces pattern space with next input line, skip remaining commands.
    • e.g.: sed 'n;d' deletes every *even*-numbered line.
  • N appends next line to pattern space (with embedded newline). Useful for multiline processing.
    • e.g.: sed 'N;s/\n/ /' joins every two consecutive lines.
  • P prints the first part (up to newline) of the pattern space. Used after N.
    • e.g.: sed -n 'N;P' prints only the first line of each pair.
  • D deletes the first part (up to newline) of the pattern space. Restarts cycle if content remains.
    • e.g.: sed 'N;/error/D' deletes leading lines in a pair if “error” is found.
  • h copies pattern space to hold space (overwriting). H appends with newline.
  • g copies hold space to pattern space (overwriting). G appends with newline.
    • e.g.: sed -n '/start/{h; /end/{g; p}}' prints lines between “start” and “end” inclusively.
  • x exchanges hold space and pattern space.
    • e.g.: sed '/swap/{x;p;x}' prints hold space when “swap” is matched.
  • l prints pattern space in unambiguous form (non-printable as hex, wraps long lines).
    • e.g.: sed -n l shows hidden characters.
  • : <label> defines a label for branching. Requires a single colon.
  • b <label> branches to <label> (or end of script if no label).
  • t <label> branches to <label> only if a substitution succeeded since last input line or t.
    • e.g.: sed ':a; s/foo/bar/; ta; s/baz/qux/' repeatedly replaces “foo” until none remain, then replaces “baz”.
  • e [<command>] executes a command and sends output to output stream. Without argument, executes pattern space.
    • e.g.: sed 's/.*/date +%s/e' replaces each line with the current Unix timestamp.
  • F prints the filename being processed (useful with multiple files).
    • e.g.: sed -n F *.log prints all filenames in a directory.
  • Q [<exit-code>] quits without printing pattern space (like q but silent).
    • e.g.: sed '/match/Q42' exits with code 42 upon first “match”.
  • v <version> fails if sed version is less than <version> (e.g., v 4.2).
  • z zaps (empties) the pattern space. Useful for multiline processing.
    • e.g.: sed '/pattern/{z;d}' deletes lines after “pattern” is found.
  • # denotes a comment until next newline.
    • e.g.: sed 's/A/B/ # Replace A' ignores text after #.
  • { } groups commands into a block. Must appear as separate commands.
    • e.g.: sed '/start/{s/A/B/; s/C/D/}' applies substitutions only to lines containing “start”.
  • T <label> branches to <label> only if no substitutions succeeded since last input line or T (opposite of t).
Notes
  1. Most commands accept addresses (e.g., <start>,<end> or /<regex>/) to restrict operation.
  2. a, i, and c are “greedy” — text arguments span lines until an unescaped newline.
    • To use multiple commands, separate each command with a new line. Input a new line in a shell by pressing Esc and then ↵ Enter separately.
  3. Hold space commands (h, g, etc.) enable advanced stateful operations.
  4. Frequency ranking is estimated based on common use cases (e.g., s is most frequent).

Addresses

  • /<regex>/ selects lines matching a regular expression pattern. Used to filter lines for command application.
    • e.g.: sed -n '/error/p' prints lines containing “error”.
    • e.g.: sed '/^#/d' deletes comment lines starting with #.
    • In case a different delimiter needs to be used, the starting character needs to be escaped by a backslash like so: \!/usr/include/[^/]+\.h!
  • <n> targets a specific line number.
    • e.g.: sed '42s/old/new/' replaces “old” with “new” only on line 42.
    • e.g.: sed '1i\Header' inserts “Header” before line 1.
    • 0 and $ refers to the start and the end of the file.
  • <start>,<end> operates on lines from start to end (inclusive). Numbers, regexes, or $ (EOF) allowed.
    • e.g.: sed '10,20d' deletes lines 10–20.
    • e.g.: sed '5,$s/foo/bar/' substitutes “foo” → “bar” from line 5 to EOF.
    • e.g.: sed -n '/error/,$p' prints from first “error” to EOF.
  • ! applies commands to lines NOT matching the address.
    • e.g.: sed '/pattern/!d' deletes lines not containing “pattern”.
    • e.g.: sed '3,5!s/foo/bar/' substitutes “foo” → “bar” except on lines 3–5.
  • <address>,+<n> selects address plus n following lines (GNU Extension)
    • e.g.: sed '/START/,+3d' deletes “START” line + next 3 lines
    • e.g.: sed '10,+5s/foo/bar/' substitutes in lines 10–15
  • <start>~<step> selects every step lines starting at start (GNU Extension)
    • e.g.: sed '1~2d' deletes every odd line (1,3,5...)
    • e.g.: sed '2~5s/^/# /' comments lines 2,7,12,17...
Summary Table of sed Address Types
Type Syntax Example Explanation
Regex /pattern/ sed '/foo/d' Delete lines containing “error”
Single Line 5 sed '5q' Quit after line 5
Regex Range /a/,/b/ sed '/start/,/end/p' Print between markers
Line Range 3,7 sed '3,7s/a/b/' Substitute in lines 3–7
Step start~step sed '1~3d' Delete every 3rd line starting at 1
Offset addr,+n sed '/err/,+2d' Delete error line + next 2 lines
Special 0, $ sed '$s/old/new/' Substitute in last line
Combined 5,/x/ sed '5,/end/d' Delete from line 5 to next “end”
Negation ! sed '/keep/!d' Delete lines not containing “keep”

Examples

Replace `backticks` with <code> Tags

Suppose the working directory contains the file file.txt:

`sed` is a very powerful text processor.
It is commonly used to perform text transformations.
`sed` is inspired by `grep`.

First, the texts wrapped around backticks can be obtained using the -E flag, which enables extended regular expressions[6] (aka. regex).

 $ sed -E 's/`.+`/FOUND/g' file.txt
FOUND is a very powerful text processor.
It is commonly used to perform text transformations.
FOUND.

The g flag (global) performs the substitution infinitely many times instead of just once for each line. Notice the last line is not matched correctly since .+ is greedily evaluated[7]. This can be resolved by using [^`], which matches all characters except `, instead of . which matches all characters:

 $ sed -E 's/`[^`]+`/FOUND/g' file.txt
FOUND is a very powerful text processor.
It is commonly used to perform text transformations.
FOUND is inspired by FOUND.

Next, we add regex group 1 to the inner texts wrapped inside the backticks, and set the replacement text to <code>\1</code>. \1 expands to the content of regex group 1.

 $ sed -E 's/`([^`]+)`/<code>\1</code>/g' file.txt
sed: -e expression #1, char 23: unknown option to `s'

The error occurs because the replacement text contains the character /, which is used as the separator for the s command. The desired result can be obtained by escaping it using a backslash:

 $ sed -E 's/`([^`]+)`/<code>\1<\/code>/g' file.txt
<code>sed</code> is a very powerful text processor.
It is commonly used to perform text transformations.
<code>sed</code> is inspired by <code>grep</code>.

Alternatively, we can change the separator to @:

 $ sed -E 's@`([^`]+)`@<code>\1</code>@g' file.txt
<code>sed</code> is a very powerful text processor.
It is commonly used to perform text transformations.
<code>sed</code> is inspired by <code>grep</code>.

Finally, we can use the -i flag to edit the file directly:

 $ sed -E 's@`([^`]+)`@<code>\1</code>@g' -i file.txt

FizzBuzz

FizzBuzz is a famous problem that involves 4 rules:

  1. if a number is divisible by 15, print FizzBuzz;
  2. if a number is divisible by 3, print Fizz;
  3. if a number is divisible by 5, print Buzz;
  4. otherwise, print the number itself.

In this example, FizzBuzz is performed on the first 50 positive integers, which are prepared with seq 50. The numbers can be further processed by checking whether the line number is a multiple of 15, 3, or 5:

sed -E '
15~15{s@.+@FizzBuzz@; b}
3~3{s@.+@Fizz@; b}
5~5s@.+@Buzz@'

~15 performs the specified command following itself every 15 lines. The 15 before the ~ sign indicates which line to start counting. In this case, s@.+@FizzBuzz@; b is performed every 15 lines starting with the 15th line.

s@.+@FizzBuzz@ performs a substitution. With the -E flag, the regex .+ can be used to match for the entire line. The entire line is then replaced with FizzBuzz. Finally, the b command (b stands for branch) tells sed to skip the remaining commands and process the next line.

The same is done for line numbers divisible by 3 and 5. Note that for 5~5s@.+@Buzz@, b is no longer needed since all conditions have already been processed.

The commands can be further improved by using c (which stands for change):

sed '15~15c FizzBuzz
3~3c Fizz           
5~5c Buzz'

Note the lack of -E since regexes are no longer in use.

And finally, pr -5t prints out the results in 5 columns. The full command is now:

seq 50 | sed -E '15~15c FizzBuzz
3~3c Fizz
5~5c Buzz' | pr -5t

The output is:

1             11            Fizz          31            41
2             Fizz          22            32            Fizz
Fizz          13            23            Fizz          43
4             14            Fizz          34            44
Buzz          FizzBuzz      Buzz          Buzz          FizzBuzz
Fizz          16            26            Fizz          46
7             17            Fizz          37            47
8             Fizz          28            38            Fizz
Fizz          19            29            Fizz          49
Buzz          Buzz          FizzBuzz      Buzz          Buzz

See Also

References

  1. GNU sed - GNU Project - Free Software Foundation, Free Software Foundation, Inc., 2020 (Accessed: 2025-06-20)
  2. The sed FAQ, Section 2.1, Eric Pement, 2003 (Accessed: 2018-06-27)
  3. 3.0 3.1 3.2 sed - Wikipedia, Wikipedia, 2025 (Accessed: 2025-06-20)
  4. A Brief History of sed, Sourcerer Blog, 2018 (Accessed: 2025-06-20)
  5. ssed, Launchpad, 2005 (Accessed: 2025-06-20)
  6. sed(1) - Linux manual page, man7.org, 2022 (Accessed: 2025-06-20)
  7. Regular Expression Tutorial Part 5: Greedy and Non-Greedy Quantification, Andrew Johnson, 2001 (Accessed: 2025-06-20)