Home > OS >  Replace Indented text using SED
Replace Indented text using SED

Time:10-12

I am looking at replacing some indented lines in a Yaml file using sed.

      resources:
        limits:
          cpu: 500m
          memory: 512Mi
        requests:
          cpu: 250m
          memory: 256Mi

Yaml is strict about its indentation and will want to know how I can accomplish a replacement of the text after example "limits:"

I have tried '0,/cpu:.*m/s//cpu: 900m/' and '/limits:/!b;n;s//ccpu: 900m'

'0,/cpu:.*m/s//cpu: 900m/' outputs:

          resources:
        limits:
          cpu: 900m
          memory: 512Mi
        requests:
          cpu: 250m
          memory: 256Mi

The only issue I have with this is I will want to specify the replacement should be done on the example CPU for limits and not for the requests.

So I tried '/limits:/!b;n;s//ccpu: 900m' which outputs:

          resources:
        limits:
cpu: 900m
          memory: 512Mi
        requests:
          cpu: 250m
          memory: 256Mi

Notice how it is not properly indented? How can I achieve this by leaving the indentation as it is and also if I can specify 1st and 2nd lines after "limits:" or "requests:" that will be nice.

CodePudding user response:

If you cannot install yaml parsing tools such as yq, you can use this gnu-sed solution:

sed -E '/limits:/!b;n;s/^([[:blank:]]*cpu: ).*/\1900m/' file.yml

      resources:
        limits:
          cpu: 900m
          memory: 512Mi
        requests:
          cpu: 250m
          memory: 256Mi

Breakdown:

  • /limits:/!b: Search for text limits: otherwise branch to end of script
  • n: Read/append the next line of input into the pattern space
  • s/.../.../: Do this substitution
    • ^: Match start
    • ([[:blank:]]*cpu: ): Match 0 or more whitespaces followed by text cpu: . Capture this in capture group #1
    • .*: Match remaining text till end of line
    • /\1900m/: Replace with back-reference of capture group #1 i.e. \1 followed by new value 900m

CodePudding user response:

With your shown samples and in GNU awk you can try following awk code. Though tools which know yaml files are recommended in case they can't be used this will be helpful.

awk -v RS="^$" '
match($0,/(^|\n)([[:space:]] resources:\n[[:space:]] limits:\n[[:space:]] cpu: )[^\n] (\n.*)$/,arr){
  printf("%s",arr[1] arr[2] "900m" arr[3])
}
' Input_file

Here is the Online Demo for used regex (^|\n)([[:space:]] resources:\n[[:space:]] limits:\n[[:space:]] cpu: )[^\n] (\n.*)$ adding it here for better understanding for regex.

Explanation:

  • (^|\n): Creating 1st capturing group which matches either starting of value OR new line.
  • ([[:space:]] resources:\n[[:space:]] limits:\n[[:space:]] cpu: ): Creating 2nd capturing group which matches spaces followed by resources followed by new line followed by spaces followed by limits: followed by new line followed by spaces cpu:
  • [^\n] : Matching everything before new line.
  • (\n.*)$: Creating 3rd capturing group new lines followed by everything till end of line.

CodePudding user response:

Using any awk:

$ awk 'f{sub(/[^ ] $/,"900m"); f=0} /limits:/{f=1} 1' file
      resources:
        limits:
          cpu: 900m
          memory: 512Mi
        requests:
          cpu: 250m
          memory: 256Mi
  • Related