Search code examples
textsed

sed: how to replace last digits of the found pattern


Colleagues, can't find a solution:

I have a file with equal sequence: ..."TargetGroupArn": "randomsetishere-green/e23cf778ec867027", "Weight": 100 }, { "TargetGroupArn": "randomsetishere-blue/a474ffa6a7667868", "Weight": 0 }....

I need to search and replace Weight value (1....100) for -green.

As I see, I need to search for sequence -green/[any symbols]", "Weight": [1-3 number symbols] and replace with -green -green/[the same set of symbols]", "Weight": [my own number].

It's not hard to search for required: 's/-green\/.*Weight": [0-9]*'

No idea how to "save" "the same any symbols" found and add it to replacement pattern using sed.

It's not hard to search for required: 's/-green\/.*Weight": [0-9]*'

But how to return back something like this (bold must be replaced with already found) 's/-green\/.*Weight": 100'

I was thinking for search for pattern and reverse at the end of this pattern ": [0-9]*" to ": 100"

UPD:

jq is the best option, but can't edit in place, while updating value still not succeed:

[ { "Type": "forward", "Order": 1, "ForwardConfig": { "TargetGroups": [ { "TargetGroupArn": "arn:aws:elasticloadbalancing:us-east-rgetgroup/services-stage-bpm-blue/e23cf774ec867027", "Weight": 1 }, { "TargetGroupArn": "arn:aws:elasticloadbalancing:us-east-rgetgroup/services-stage-bpm-green/a474ffa6a753f868", "Weight": 999 } ], "TargetGroupStickinessConfig": { "Enabled": false, "DurationSeconds": 3600 } } } ]

with jq '.[]|.ForwardConfig.TargetGroups[]|select(.TargetGroupArn|contains("-green"))|.Weight |=555'

result

{ "TargetGroupArn": "arn:aws:elasticloadbalancing:us-east-rgetgroup/services-stage-bpm-green/a474ffa6a753f868", "Weight": 555 }

  • but I need all, not only filtered-out.

Solution

  • This replaces the number with 999:

    sed 's=\(-green/[^"]*", "Weight": \)[0-9]*=\1999='
    
    1. It uses = instead of / as the substitution delimiter to prevent the need of backslashes.
    2. It uses [^"]* instead of .* otherwise the .* would have matched up to the last Weight on the line.
    3. It captures the string up to the number and uses the captured value in the replacement (\1). This way, everything up to the number itself remains the same.

    But,

    as your input seems to be JSON, a jq solution would be safer and not sensitive to whitespace formatting.

    For example, if the whole input just consisted of an array of the objects you showed, the following would replace the Weight with 999:

    jq '(.[] | select(.TargetGroupArn|contains("-green/")) | .Weight) |= 999' file.json
    

    Update

    For the structure you posted, just a pair of parentheses was missing:

    '(.[].ForwardConfig.TargetGroups[]|select(.TargetGroupArn|contains("-green"))|.Weight) |=555'