What Does an Empty Regular Expression in a Sed Address Range Do?

Viewed 156

The following command sed -E '/# Section [134]/, // s/foo/bar/' <input_file> accomplishes the following

Input

# Section 1

- foo
- Unimportant Item

# Section 2

- foo
- Unimportant Item

# Section 3

- foo
- Unimportant Item

# Section 4

- foo
- Unimportant Item

# Section 5

- foo
- Unimportant Item

Output

# Section 1

- bar
- Unimportant Item

# Section 2

- foo
- Unimportant Item

# Section 3

- bar
- Unimportant Item

# Section 4

- bar
- Unimportant Item

# Section 5

- foo
- Unimportant Item

I am unsure of how this command works, specifically the empty regular expression in the address range. What I understand so far is Sed will first look for a portion of the document that matches the following regex /# Section [134]/, if it matches, it will begin the substitution looking for matches for foo and replacing them with bar. The second portion of the address range, as far as I am aware, is the stopping point, but in this case it is empty. I read here that an empty regular expression "repeats the last regular expression match", but I don't exactly know what this means, or how it affects this specific Sed command. How does the address range know that the stopping point is after each section? What regex is // repeating?

2 Answers

Let me simplify the input file as:

Line1
Line2
Line3
Line4
Line5

and the test script as:

sed -n "/[134]/,//p"

which will print the all lines, corresponding to your test results. As noted, the empty regex repeats the previous regex, then the sed command above is equivalent to:

sed -n "/[134]/,/[134]/p"

BTW the address range operator of sed works as follows:

  • If the left address matches, returns true without evaluating right address on the same line (unlike the range operator of awk which evaluates the right condition immediately on the same line).

Let's see how the operator works line by line.

  • On the first line Line1, the left start address matches and returns true.
  • On the second line, the right stop address is evaluated without match then the operator keeps true.
  • On the third line, the right stop address matches then it changes the status to false (after printing the line).
  • On the fourh line, the left start address matches and returns true again.
  • On the fifth line, the right stop address does not match and keeps true.

If you change the regex to /[135]/, you will see a different result. (Line1, 2, 3, 5 will be printed skipping Line4.)

Using an empty regex is a shorthand for repeating the latest matching regex. So your script is an abbreviated (and more idiomatic, and less buggy) version of the longhand

sed -E '/# Section [134]/,/# Section [134]/ s/foo/bar/' <input_file>

which says to perform the substitution s/foo/bar/ in the range of lines starting with one occurrence of the regex, through to the next occurrence of the same regex (and starting again if there is a third one up through the fourth one, etc).

This is also available in the s/// command, so a fairly common idiom is

sed '/foo/ s//bar/'

which says to search for foo and then replace foo with bar. (This particular example is not particularly useful, but there are situations where this saves a lot of typing.)

Related