Home > Net >  bash search and replace a line after a certain line
bash search and replace a line after a certain line

Time:02-03

I have a big yaml file containing multiple declaration blocks, related to different services.

The structure is similar to the following (but repeated for multiple applications):

- name: commerce-api
  type: helm
  version: 0.0.5

I would like to find the block of code that is containing commerce-api and replace the version property value with something else.

The thing is, I wrote this script:

bumpConfig() {
  LINE=$(awk "/- name: $1$/{print NR   $2}" "$CONFIG_YML")
  sed -i "" -E "${LINE}s/version: $3.*$/\version: $4/" "$CONFIG_YML"
}

bumpConfig "commerce-api" 2 "$OLD_APP_VERSION" "$NEW_APP_VERSION"

Which is kind of allowing me to do what I want, but the only problem is that, the property version is not always on the third line.

How can I make my script to look for the first occurrence of version given the service name to be commerce-api?

Is this even possible using awk?

CodePudding user response:

Adding some variation to the input file:

$ cat config.yml
- name: commerce-api-skip
  type: helm
  version: 0.0.5
    - name: commerce-api
      type: helm
      bogus line1: bogus value1
      version: 0.0.5
      bogus line2: bogus value2
- name: commerce-api-skip-too
  type: helm
  version: 0.0.5

One awk idea:

bumpConfig() {
    awk -v name="$1" -v old="$2" -v new="$3" '
    /- name: /                { replace=0
                                if ($NF == name)
                                   replace=1
                              }
    replace && $1=="version:" { if ($NF == old)
                                   $0=substr($0,1,index($0,old)-1) new
                              }
    1
    ' "${CONFIG_YML}"
}

Taking for a test drive:

CONFIG_YML='config.yml'

name='commerce-api'
OLD_APP_VERSION='0.0.5'
NEW_APP_VERSION='0.0.7'

bumpConfig "${name}" "${OLD_APP_VERSION}" "${NEW_APP_VERSION}"

This generates:

- name: commerce-api-skip
  type: helm
  version: 0.0.5
    - name: commerce-api
      type: helm
      bogus line1: bogus value1
      version: 0.0.7
      bogus line2: bogus value2
- name: commerce-api-skip-too
  type: helm
  version: 0.0.5

Once OP is satisfied with the result:

  • if running GNU awk the file can be updated 'in place' via: awk -i inplace -v name="$1" ...
  • otherwise the output can be saved to a temp file and then copy the temp file over the original: awk -v name="$1" ... > tmpfile; mv tmpfile "${CONFIG_YML}"

CodePudding user response:

Entirely in sed

sed -i '' "s/^version: $3/version: $4/' "$CONFIG_YML"

/^- name: $1\$/,/^- name:/ restricts the s command to just the lines between the requested name and the next - name: line.

CodePudding user response:

#!/bin/bash

OLD_APP_VERSION=0.0.5
NEW_APP_VERSION=0.0.7
CONFIG_YML=config.yml

bumpConfig() {
    gawk -i inplace -v name="$1" -v old="$2" -v new="$3" '
        1
        /^- name: / && $3 == name {
            while (getline > 0) {
                if (/^  version: / && $2 == old)
                    $0 = "  version: " new
                print
                if (!NF || /^-/ || /^  version: /)
                    break
            }
        }
    ' "${CONFIG_YML}"
}

bumpConfig commerce-api "${OLD_APP_VERSION}" "${NEW_APP_VERSION}"
  • Related