calvinkrishy
calvinkrishy

Reputation: 3928

sed: Replace part of a line

How can one replace a part of a line with sed?

The line

DBSERVERNAME     xxx

should be replaced to:

DBSERVERNAME     yyy

The value xxx can vary and there are two tabs between dbservername and the value. This name-value pair is one of many from a configuration file.

I tried with the following backreference:

echo "DBSERVERNAME    xxx" | sed -rne 's/\(dbservername\)[[:blank:]]+\([[:alpha:]]+\)/\1 yyy/gip'

and that resulted in an error: invalid reference \1 on `s' command's RHS.

Whats wrong with the expression? Using GNU sed.

Upvotes: 48

Views: 70018

Answers (7)

Jeremy Stein
Jeremy Stein

Reputation: 19661

This works:

sed -rne 's/(dbservername)\s+\w+/\1 yyy/gip'

(When you use the -r option, you don't have to escape the parens.)

Bit of explanation:

  • -r is extended regular expressions - makes a difference to how the regex is written.
  • -n does not print unless specified - sed prints by default otherwise,
  • -e means what follows it is an expression. Let's break the expression down:
    • s/// is the command for search-replace, and what's between the first pair is the regex to match, and the second pair the replacement,
    • gip, which follows the search replace command; g means global, i.e., every match instead of just the first will be replaced in a line; i is case-insensitivity; p means print when done (remember the -n flag from earlier!),
    • The brackets represent a match part, which will come up later. So dbservername is the first match part,
    • \s is whitespace, + means one or more (vs *, zero or more) occurrences,
    • \w is a word, that is any letter, digit or underscore,
    • \1 is a special expression for GNU sed that prints the first bracketed match in the accompanying search.

Upvotes: 68

Mirage
Mirage

Reputation: 31548

Try this

sed -re 's/DBSERVERNAME[ \t]*([^\S]+)/\yyy/ig' temp.txt

or this

awk '{if($1=="DBSERVERNAME") $2 ="YYY"} {print $0;}' temp.txt

Upvotes: 0

potong
potong

Reputation: 58371

This might work for you:

echo "DBSERVERNAME     xxx" | sed 's/\S*$/yyy/'
DBSERVERNAME     yyy

Upvotes: 1

Vicky
Vicky

Reputation: 13244

Others have already mentioned the escaping of parentheses, but why do you need a back reference at all, if the first part of the line is constant?

You could simply do

sed -e 's/dbservername.*$/dbservername yyy/g'

Upvotes: 10

Pesto
Pesto

Reputation: 23880

You shouldn't be escaping your parens. Try:

echo "DBSERVERNAME    xxx" | sed -rne 's/(dbservername)[[:blank:]]+([[:alpha:]]+)/\1 yyy/gip'

Upvotes: 1

Matthew Scharley
Matthew Scharley

Reputation: 132254

You shouldn't be escaping things when you use single quotes. ie.

echo "DBSERVERNAME    xxx" | sed -rne 's/(dbservername[[:blank:]]+)([[:alpha:]]+)/\1 yyy/gip'

Upvotes: 1

apandit
apandit

Reputation: 3344

You're escaping your ( and ). I'm pretty sure you don't need to do that. Try:

sed -rne 's/(dbservername)[[:blank:]]+\([[:alpha:]]+\)/\1 yyy/gip'

Upvotes: 2

Related Questions