Akhmad
Akhmad

Reputation: 35

How to prevent replacement by subsequent s/// (empty pattern for replacement) in sed?

a=a
b=ab
c=''
d=''
echo ac | sed "s/$a/$b/;"
abc
echo ac | sed "s/$a/$b/; s/$c/$d/"
bc

sed removes the character 'a' in the last example, because when sed is passed the subsequent s command with an empty pattern, the previous one is used, in this case, $a instead empty $c, which is 'a'.

The POSIX specification for sed

If an RE is empty (that is, no pattern is specified) sed shall behave as if the last RE used in the last command applied (either as an address or as part of a substitute command) was specified.

In a real script, variables $c $d can be either empty or defined. For defined variables $c $d a subsequent s command must be executed, but how to prevent replacement by a subsequent s command for the case of empty variables in sed?

Upvotes: 0

Views: 78

Answers (2)

KamilCuk
KamilCuk

Reputation: 141030

Just don't do it if the variable is empty:

sed "s/$a/$b/; ${c:+s/$c/$d/}"

${parameter:+word} is one of variable expansions - if var is null or unset, if expands to nothing, otherwise the expansion of word is used.

Upvotes: 1

Jon
Jon

Reputation: 3671

Strictly speaking, sed has no sensible way of making the second substitution conditional on the emptiness of $c. sed isn't designed for that kind of thing.

However, you could bodge up something which does what you want. For example, you could use a 'noop' operation to reset the default regular expression to something very unlikely:

$ echo ac | sed "s/$a/$b/; /^x\{80\}$/h; s/$c/$d/"
abc

This is a proper bodge though. For one thing, sed doesn't have a real noop - I've abused h in this example. And for another thing, you always run the risk of 'very unlikely' actually happening.

You'd be better off checking $c in a shell wrapper and, if it is empty, invoking sed with only the first substitution.

Upvotes: 1

Related Questions