2

My final goal is to get a bunch of text above the COMMIT line in /etc/ufw/before.rules. I am trying to replace the COMMIT with something like this: TEXT I WANT\nCOMMIT

I see this as an easy sed command: echo COMMIT | sed "s@COMMIT@${morerules}@g"

I have set the variable morerules to a string like this:

morerules="""
### Start HTTP ###
# Enter rule
-A ufw-before-input -p tcp --dport 80 -j ufw-http
-A ufw-before-input -p tcp --dport 443 -j ufw-http
# Limit connections per Class C
-A ufw-http -p tcp --syn -m connlimit --connlimit-above 50 --connlimit-mask 24 -j ufw-http-logdrop
# Limit connections per IP
-A ufw-http -m state --state NEW -m recent --name conn_per_ip --set
-A ufw-http -m state --state NEW -m recent --name conn_per_ip --update --seconds 10 --hitcount 20 -j ufw-http-logdrop
# Limit packets per IP
-A ufw-http -m recent --name pack_per_ip --set
-A ufw-http -m recent --name pack_per_ip --update --seconds 1 --hitcount 20 -j ufw-http-logdrop
# Finally accept
-A ufw-http -j ACCEPT
# Log
-A ufw-http-logdrop -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix \"[UFW HTTP DROP]\"
-A ufw-http-logdrop -j DROP
### End HTTP ##
"""

As you can see, I added a backslash to the quotations marks. Setting the variable is successful. When I run the command from above echo COMMIT | sed "s@COMMIT@${morerules}@g", this is the output:

sed: -e expression #1, char 9: unterminateds' command`

Is the error with my string or with my sed command? Also, I know other people have gotten this error, but none of their fixes seem to work.

pledab
  • 120
  • 1
  • 13
  • 1
    You may find [insert multiple lines into a file after specified pattern using shell script](https://stackoverflow.com/questions/22497246/insert-multiple-lines-into-a-file-after-specified-pattern-using-shell-script) applicable. As it is, each line in your argument to `sed -e` is being passed as a separate expression, so you get the error you do because the first line has no closing `@`. – Charles Duffy Aug 23 '17 at 15:40
  • You may also find [BashFAQ #21](http://mywiki.wooledge.org/BashFAQ/021) applicable; `sed` isn't always the right tool for the job. – Charles Duffy Aug 23 '17 at 15:52

1 Answers1

4

To place a literal backslash before each newline in your replacement text, thus telling sed that it should be considered part of the same expression:

orig=$'\n'; replace=$'\\\n'
sed "s@COMMIT@${morerules//$orig/$replace}@g"

(Placing the values in variables makes it easier to implement this in a way that works across multiple versions of bash).

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • Thank you so much! I thought the newline in the string would be automatically converted, but it makes sense that it's interpreted as multiple commands. – pledab Aug 23 '17 at 16:01