Tuesday, January 4, 2022

[SOLVED] sed / awk match second occurrence of regex in a file, and replace whole line

Issue

Trying to have sed or awk do the following:

  1. Look through file
  2. Capture on a string + regex (remote_addrs.*)
  3. Replace the whole line with something different, so "a line that has "remote_addrs" and anything after it" replace it.

Example file:

dog
cat
remote_addrs = 1.1.1.1
moose
remote_addrs = 2.2.2.2
woodchuck

Want it changed to this: Example file:

dog
cat
remote_addrs = 1.1.1.1
moose
remote_addrs = 3.3.3.3
woodchuck

Tried using the following:

sed -z 's/remote_addrs.*/remote_addrs\ =\ 3.3.3.3/2' file
sed ':a;N;$!ba;s/remote_addrs.*/remote_addrs\ =\ 3.3.3.3/2' file

but sed refuses to replace everything after that occurrence. This seems to only work with a single string.

This MUST be accomplished without giving specific line numbers, the line position of "remote_addrs" must be variable.


Solution

You are using a GNU sed, so I am also posting a GNU sed solution:

sed -z 's/remote_addrs.*/remote_addrs = 3.3.3.3/2m' file

Note:

  • \3 (used in the initial version of your now edited question) is a backreference to Group #3, and there no single group in your regex. So, the escape should be removed
  • You need not escape spaces
  • \z makes line breaks part of pattern space, and thus . matches them. You need to turn on "multiline" mode, and add m flag, so that a . pattern could not match line break chars.

See the online demo:

#!/bin/bash
s='dog
cat
remote_addrs = 1.1.1.1
moose
remote_addrs = 2.2.2.2
woodchuck'
 
sed -z 's/remote_addrs.*/remote_addrs = 3.3.3.3/2m' <<< "$s"

Output:

dog
cat
remote_addrs = 1.1.1.1
moose
remote_addrs = 3.3.3.3
woodchuck


Answered By - Wiktor Stribiżew