4

I have a script that I'm using to perform some iptables changes across servers. In the script I have a sed command to find a string and insert iptables rule before that line.

The problem I'm having is that the file I'm editing is a yaml file and I need to have a ' and ' in the line.

If I remove the ' from what I'm inserting, it works.

$ sed 's/.*output_snat_lo.conf:.*/- -t nat -A PREROUTING -d 192.168.1.1 -j DNAT --to-destination 10.0.0.1\n&/' file.yaml


     - '-t nat -A POSTROUTING -s 192.168.1.25/32 -d 10.0.0.1 -j SNAT --to-source 172.1.1.1'
     - -t nat -A PREROUTING -d 192.168.1.1 -j DNAT --to-destination 10.0.0.1
  output_snat_lo.conf:

However, if I try to escape it with slashes or putting it within double quotes, double quotes with slashes I can't get the ' to print but rather give send invalid flag options.

This is what I'm trying to insert.

- '-t nat -A PREROUTING -d 192.168.1.1 -j DNAT --to-destination 10.0.0.1'\n&/' file.yaml

Any suggestions/tricks? I feel like I've done this in the past but can't recall how.

0

2 Answers 2

5

close the single quote you are putting the regexp in, escape a single quote, and open it again

$ echo "a'b" | sed 's/'\''/X/'
aXb

$ echo "aXb" | sed 's/X/'\''/'
a'b
0
4

You don't need to escape in sed, where ' has no special significance. You need to escape it in bash.

$ sed -e "s/'/singlequote/g" <<<"'"
singlequote

You can see here that the double quotes protect the single quote from bash, and sed does fine with it. Here's what happens when you switch the single quotes.

$ sed -e 's/'/singlequote/g' <<<"'"
>

The strange thing about ' in bourne like shells (all?) is that it functions less like " and more like a flag to disable other character interpretation until another ' is seen. If you enclose it in double quotes it won't have it's special significance. Observe:

$ echo 'isn'"'"'t this hard?'
isn't this hard?

You can also escape it with a backslash as shown in the other answer. But you have to leave the single quoted block before that will work. So while this seems like it would work:

echo '\''

it does not; the first ' disables the meaning of the \ character.

I suggest you take a different approach. sed expressions can be specified as command line arguments - but at the expense of having to escape from the shell. It's not bad to escape a short and simple sed expression, but yours is pretty long and has a lot of special characters.

I would put your sed command in a file, and invoke sed with the -f argument to specify the command file instead of specifying it at the command line. http://man7.org/linux/man-pages/man1/sed.1.html or man sed will go into detail. This way the sed commands aren't part of what the shell sees (it only sees the filename) and the shell escaping conundrum disappears.

$ cat t.sed
s/'*/singlequote(s)/g

$ sed -f t.sed <<<"' ' '''"
singlequote(s) singlequote(s) singlequote(s)

Not the answer you're looking for? Browse other questions tagged .