bashshell

Append to matching line only if line doesn't contain keyword


I have a file let's call it input.txt. It has many lines, but the only relevant line contains a model statement;

height ~ mu gender

It may also contain;

height !n ~ mu date_birth !r g

So the consistent factor to identify the line in regex would be ^height.*~.*$. At least that is what I have devised so far.

I would like to append !r g to the end line only if !r g wasn't already present. I tried to mix answers from here, here and here, but I can't figure it out. I would prefer a single command. Have also been playing around with complicated awk's and sed's but I feel this is overly simple that it doesn't need to be too difficult for someone with experience.

Desired result(s):

If height ~ mu gender then height ~ mu gender !r g.

If height !bin ~ mu date_birth !r g then nothing needs to happen.

If height !bin ~ mu gender then height !bin ~ mu gender !r g

EDIT:

So far I tried;

sed '/^height.*~.*!r.*$/ ! s/$/!r g/' input.txt correctly skips line if !g is present but appends it to each line in input.txt.

sed '/^height.*$/s/$/!r g/' input.txt, correctly appends only to the matching line, but also if !r g was already present.


Solution

  • sed '/^y.*~.*$/{/!r g/!{s/.*/& !r g/}}' input.txt
    

    E.g.

    $ cat input.txt
    y !n ~ d e f !r g
    y ~ a b c
    
    $ sed '/^y.*~.*$/{/!r g/!{s/.*/& !r g/}}' input.txt
    y !n ~ d e f !r g
    y ~ a b c!r g
    

    UPDATE

    Above sed command will consider all the lines with pattern ^y.*~.*$, and append !r g to the end only if the line does not contain !r g in any part of the line.

    To change the lines filtered, simply update the starting regex ^y.*~.*$ into what you need.