Pranav Patil Pranav Patil - 1 month ago 8
Bash Question

Getting unterminated 's' command with sed (bash)

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: unterminated
s' 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.

Answer Source

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).