1

So I have multiple sed commands I will like to put together as one. Any pointer will be appreciated, I believe this is a sort of advanced SED and I have tried to no success:

sed -E '/limits:/!b;n;s/^([[:blank:]]*cpu: ).*/\\1900m/' mychart.yaml
sed -E '/limits:/!b;n;n;s/^([[:blank:]]*memory: ).*/\\1900Mi/' mychart.yaml
sed -E '/requests:/!b;n;s/^([[:blank:]]*cpu: ).*/\\1700m/' mychart.yaml
sed -E '/requests:/!b;n;n;s/^([[:blank:]]*memory: ).*/\\1500Mi/' mychart.yaml

Below is the mychart.yaml context I am using the above commands to replace the values:

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

Thank you all!

Seun
  • 73
  • 1
  • 5
  • 1
    You can do multiple commands in a single `sed` invocation: `sed -e cmd -e cmd -e cmd -e cmd` works well. – William Pursell Oct 12 '22 at 18:16
  • That did not work for it. Perhaps because I am using the -E flag already? And my replacement did not work well except with the -E, I am using indentation, which must be obeyed in yaml – Seun Oct 12 '22 at 18:17
  • `sed -E -e cmd -e cmd ...` – William Pursell Oct 12 '22 at 18:17
  • 2
    But `sed` is the wrong tool for this. Use a yaml parser, or at least use `awk`. – William Pursell Oct 12 '22 at 18:18
  • "sed -E -e cmd -e cmd" did not work... – Seun Oct 12 '22 at 18:33
  • We dont want to install anything extra on the servers, sed is already on them, and it will be nice to just use it if possible. Thank you – Seun Oct 12 '22 at 18:34
  • FWIW I briefly marked this as a duplicate of the canonical [Combining two sed commands](https://stackoverflow.com/questions/7657647/combining-two-sed-commands) but then realized that this is a more complex question. – tripleee Oct 12 '22 at 19:03

2 Answers2

1

Your scripts cannot be trivially combined because they each contain instructions to skip the rest of the script (the b commands). You will need some refactoring to make it work.

In brief, this replaces each !b with a set of braces which say what to do when the condition matches, instead of simply saying "do nothing and skip to the end of the script if it doesn't match". Because several of these conditions overlap, they had to be further combined to do the second n after the first instead of repeating the same condition again.

sed -E -e '/limits:/{;n;s/^([[:blank:]]*cpu: ).*/\1900m/'\
       -e 'n;s/^([[:blank:]]*memory: ).*/\1900Mi/;}' \
       -e '/requests:/{;n;s/^([[:blank:]]*cpu: ).*/\1700m/' \
       -e  'n;s/^([[:blank:]]*memory: ).*/\1500Mi/;}' mychart.yaml

The doubled backslashes also looked wrong, so I switched those to single ones.

For the record, the -E option (or other options like -i or -r) don't change the fundamental syntax; you use multiple -e option to specify multiple pieces of script.

Different sed dialects have different rules for when you need newlines or semicolons e.g. around braces, so this might not work out of the box on all platforms. I tested on MacOS which is typically rather conservative and crude, so if it works there, I guess it should work most other places, too.

But as others have already pointed out, using a proper YAML parser is a much, much, much better solution.

tripleee
  • 175,061
  • 34
  • 275
  • 318
1

To combine all the sed commands I suggest a cleaner approach to put them all in a sed command text file like this:

cat parse.sed

/limits:/ {
   n
   s/^([[:blank:]]*cpu: ).*/\1900m/
   n
   s/^([[:blank:]]*memory: ).*/\1900Mi/
}
/requests:/ {
   n
   s/^([[:blank:]]*cpu: ).*/\1700m/
   n
   s/^([[:blank:]]*memory: ).*/\1500Mi/
}

Then use it as:

sed -E -f parse.sed mychart.yaml

     resources:
        limits:
          cpu: 900m
          memory: 900Mi
        requests:
          cpu: 700m
          memory: 500Mi
anubhava
  • 761,203
  • 64
  • 569
  • 643