Just use the return value of the command and use double-quotes instead of single quotes:
if ! sed -i "/$2/{s//$3/;h};"'${x;/./{x;q0};x;q1}' $1
then
echo "$3" >> $1
fi
SOURCE: Return code of sed for no match for the q command
This is treading outside my normal use of sed, so let me give an explanation of how this works, as I understand it:
sed "/$2/{s//$3/;h};"'${x;/./{x;q0};x;q1}' $1
The first /$2/
is an address - we will do the commands within {...}
for any lines that match this. As a by-product it also sets the pattern-space to $2
.
The command {s//$3/;h}
says to substitute whatever is in the pattern-space with $3
and then save the pattern-space in the "hold-space", a type of buffer within sed.
The $
after the single quote is another address - it says to do this next command on the LAST line.
The command {x;/./{x;q0};x;q1}
says:
x
= swap the hold-space and the pattern-space
/./
= an address which matches anything
{x;q0}
= swap the hold-space and the pattern-space - if this is successful (there was something in the hold-space) then q0=exit with 0 status (success)
x;q1
= swap the hold-space and the pattern-space - since this is now successful (due to the previous x) then q1=exit with 1 status (fail)
The double-quotes around the first part allow substitution for $2
and $3
. The single quotes around the latter part prevents erroneous substitution for the $
.
A bit complicated, but it seems to work AS LONG AS YOU HAVE SOMETHING IN THE FILE. An empty file will still succeed since you don't get any match on the last line.
To be honest, after all this complication... Unless the files you are working with are really long so that a double-pass would be really bad I would probably go back to the grep
solution like this:
if grep -q "^$2" $1
then
sed -i "s/^$2.*$/$3/" $1
else
echo "$3" >>$1
fi
That's a WHOLE lot easier to understand and maintain later...