0

I am trying to invoke the elements of the directory array via bash script (& sed), but it breaks:

sed: -e expression #1, char 33: unknown option to `s'

#!/bin/bash


directory=(one two three)


for m in "${directory[@]}"
do
  echo "${m}" ;

sed -i -e '45 s/$/\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n  namespace: ${m}\n  name: ${m}-api1-ingress\n  annotations:\n    nginx.ingress.kubernetes.io/use-regex: "true"\n    nginx.ingress.kubernetes.io/configuration-snippet: |\n      rewrite "(?i)/${m}/api1/(.*)" /$1 break;\n      rewrite "(?i)/${m}/api1$" / break;\n  labels:\n    Name: ${m}\n    App: test-api\n    Tier: end\nspec:\n  rules:\n  - host: www.test.com\n    http:\n      paths:\n      - backend:\n          serviceName: ${m}-test-api-1\n          servicePort: 80\n        path: /${m}/api1\n\n---\n\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n  namespace: ${m}\n  name: ${m}-api2-ingress\n  annotations:\n    nginx.ingress.kubernetes.io/use-regex: "true"\n    nginx.ingress.kubernetes.io/configuration-snippet: |\n      rewrite "(?i)/${m}/api2/(.*)" /$1 break;\n      rewrite "(?i)/${m}/api2$" / break;\n  labels:\n    Name: ${m}\n    App: test-api\n    Tier: end\nspec:\n  rules:\n  - host: www.test.com\n    http:\n      paths:\n      - backend:\n          serviceName: ${m}-test-api-2\n          servicePort: 80\n        path: /${m}/api2/g' /home/test/*.yaml;

done
user515576
  • 65
  • 6
  • Put your sed statement in double as opposed to single quotes if you are looking to expand a variable within, – Raman Sailopal Feb 11 '21 at 16:02
  • The error you see is caused by the slashes in the string you're trying to insert. I suggest you use `sed`'s `a`ppend command rather than the `s`ubstitution since it looks like you're trying to insert multiple lines after a given line. And as Raman said you'll need double-quotes if you want the variables expanded – Aaron Feb 11 '21 at 16:37
  • 1
    Reference for the `a`ppend command (replace the `$` by your line number `45` ) : https://stackoverflow.com/a/32803097/1678362. And I'm suggesting to use it because then you won't have to bother with choosing a delimiter for `s` that doesn't appear in your string & variables – Aaron Feb 11 '21 at 16:44
  • I put the sed in double quotes and replaced the `s` with `a`, but get the following error syntax error near unexpected token `?i' the sed command was the following: ```"sed -i -e '45 a/$/\napiVersion: ...... path: /${m}/api2/g'" ``` – user515576 Feb 11 '21 at 18:01
  • Use $m instead of ${m} – Raman Sailopal Feb 11 '21 at 18:15
  • What we meant with the double quotes was `sed -i -e "..."`, not `"sed -i -e '...'"`. Check [this](https://stackoverflow.com/questions/6697753/difference-between-single-and-double-quotes-in-bash/6697781#6697781) for an explanation. `${var}` works fine (although it's not necessary in your context, but some people prefer this notation that they find easier to notice/interpret) – Aaron Feb 12 '21 at 11:29
  • Also the `a` command doesn't have the same syntax as the `s` command. You should remove the leading `/$/\n`, put a backslash and linefeed instead, and remove the trailing `/g` – Aaron Feb 12 '21 at 11:38

1 Answers1

1

You should be able to use the following :

sed -i -e "45 a\
apiVersion: extensions/v1beta1\n\
kind: Ingress\n\
metadata:\n\
  namespace: ${m}\n\
  name: ${m}-api1-ingress\n\
  annotations:\n\
    nginx.ingress.kubernetes.io/use-regex: \"true\"\n\
    nginx.ingress.kubernetes.io/configuration-snippet: |\n\
      rewrite \"(?i)/${m}/api1/(.*)\" /\$1 break;\n\
      rewrite \"(?i)/${m}/api1$\" / break;\n\
  labels:\n\
    Name: ${m}\n\
    App: test-api\n\
    Tier: end\nspec:\n\
  rules:\n\
  - host: www.test.com\n\
    http:\n\
      paths:\n\
      - backend:\n\
          serviceName: ${m}-test-api-1\n\
          servicePort: 80\n\
        path: /${m}/api1\n\
\n\
---\n\
\n\
apiVersion: extensions/v1beta1\n\
kind: Ingress\nmetadata:\n\
  namespace: ${m}\n\
  name: ${m}-api2-ingress\n\
  annotations:\n\
    nginx.ingress.kubernetes.io/use-regex: \"true\"\n\
    nginx.ingress.kubernetes.io/configuration-snippet: |\n\
      rewrite \"(?i)/${m}/api2/(.*)\" /\$1 break;\n\
      rewrite \"(?i)/${m}/api2$\" / break;\n\
  labels:\n\
    Name: ${m}\n\
    App: test-api\n\
    Tier: end\n\
spec:\n\
  rules:\n\
  - host: www.test.com\n\
    http:\n\
      paths:\n\
      - backend:\n\
          serviceName: ${m}-test-api-2\n\
          servicePort: 80\n\
        path: /${m}/api2" \
/home/test/*.yaml

Note each line ending with \n\ : the \n is there for sed to add a linefeed, while the \ is there to escape the linefeed that follows and have bash parse it as decorative and avoid passing it to sed which would consider it as the end of the append command.

Also note the need to escape the double-quotes in the data so that they aren't considered as closing the quotes that contain the whole data.

Given the quantity of data and the presence of dynamically generated data, it would be preferable to store the generic data in its own file, have a first pass on that file to replace the variables with their values and then use sed or other to insert the whole transformed file (command w filename with sed). That way you wouldn't have to bother with every character your data contains that could be parsed as a meta-character as the data in the file would automatically be parsed as no more than data.

Aaron
  • 24,009
  • 2
  • 33
  • 57