132

How to escape a single quote in a sed expression that is already surrounded by quotes?

For example:

sed 's/ones/one's/' <<< 'ones thing'
Benjamin Loison
  • 3,782
  • 4
  • 16
  • 33
Thomas Bratt
  • 48,038
  • 36
  • 121
  • 139
  • 3
    possible duplicate of [Escaping single-quotes within single-quoted strings](http://stackoverflow.com/questions/1250079/escaping-single-quotes-within-single-quoted-strings) – buff Jul 01 '14 at 12:03
  • 1
    The short answer is "[you can't do that](http://www.gnu.org/software/bash/manual/bashref.html#Single-Quotes)" -- the workarounds presented all work well. – glenn jackman Jul 01 '14 at 13:42

8 Answers8

192

Quote sed codes with double quotes:

$ sed "s/ones/one's/"<<<"ones thing"   
one's thing

I don't like escaping codes with hundreds of backslashes – hurts my eyes. Usually I do in this way:

$ sed 's/ones/one\x27s/'<<<"ones thing"
one's thing
Benjamin Loison
  • 3,782
  • 4
  • 16
  • 33
Kent
  • 189,393
  • 32
  • 233
  • 301
  • 14
    This doesn't seem to work with `sed -i`, any particular reason? – SamAko Apr 25 '16 at 09:36
  • 11
    It should be noted that surrounding sed commands with double quotes allows those commands to be interpolated by the shell and may lead to unforeseen problems. – potong Sep 04 '20 at 11:36
  • 3
    this led to the answer I was looking for which ended up being: `echo "one's thing" | sed 's/\x27/\\'"'"'/g'` >> `$ one\'s thing` – matttrach Feb 24 '21 at 08:00
  • 1
    Whether or not this works with `sed -i` is a red herring. Not all `sed` dialects accept hex codes like `\x27`, irrespective of whether you pass in the `-i` flag. – tripleee Mar 17 '21 at 07:36
  • 1
    @matttrach Simplier: `echo "one's thing" | sed 's/\x27/\\&/g'` – F. Hauri - Give Up GitHub Mar 17 '21 at 12:26
60

One trick is to use shell string concatenation of adjacent strings and escape the embedded quote using shell escaping:

sed 's/ones/two'\''s/' <<< 'ones thing'

two's thing

There are 3 strings in the sed expression, which the shell then stitches together:

sed 's/ones/two'

\'

's/'

starball
  • 20,030
  • 7
  • 43
  • 238
Thomas Bratt
  • 48,038
  • 36
  • 121
  • 139
11

Escaping single quote in : 3 different ways:

From fragile to solid...

Note: This answer is based on GNU sed!!

1. Using double-quotes to enclose sed script:

Simpliest way:

sed "s/ones/one's/" <<< 'ones thing'

But using double-quote lead to shell variables expansion and backslashes to be considered as shell escape before running sed.

1.1. Specific case without space and special chars

In this specific case, you could avoid enclosing at shell level (command line):

sed s/ones/one\'s/ <<<'ones thing'

will work until whole sedscript don't contain spaces, semicolons, special characters and so on... (fragile!)

2. Using octal or hexadecimal representation:

This way is simple and efficient, if not as readable as next one.

sed 's/ones/one\o047s/' <<< 'ones thing'

sed 's/ones/one\x27s/' <<< 'ones thing'

And as following character (s) is not a digit, you coul write octal with only 2 digits:

sed 's/ones/one\o47s/' <<< 'ones thing'

3. Creating a dedicated sed script

cat <<eosedscript >sampleSedWithQuotes.sed
#!$(which sed) -f

s/ones/one's/;
eosedscript
chmod +x sampleSedWithQuotes.sed

From there, you could run:

./sampleSedWithQuotes.sed <<<'ones thing'
one's thing

This is the strongest and simpliest solution as your script is the most readable:
$ cat sampleSedWithQuotes.sed

#!/bin/sed -f

s/ones/one's/;

3.1 You coud use -i sed flag:

As this script use sed in shebang, you could use sed flags on command line. For editing file.txt in place, with the -i flag:

echo >file.txt 'ones thing'
./sampleSedWithQuotes.sed -i file.txt
cat file.txt
one's thing

3.2 Mixing quotes AND double quotes

Using dedicated script may simplify mixing quotes and double quotes in same script.

Adding a new operation in our script to enclose the word thing in double quotes:

echo >>sampleSedWithQuotes.sed 's/\bthing\b/"&"/;'

( now our script look like:

 #!/bin/sed -f
 
 s/ones/one's/;
 s/\bthing\b/"&"/;

)

then

./sampleSedWithQuotes.sed <<<'ones thing'
one's "thing"
Benjamin Loison
  • 3,782
  • 4
  • 16
  • 33
F. Hauri - Give Up GitHub
  • 64,122
  • 17
  • 116
  • 137
8

The best way is to use $'some string with \' quotes \''

eg:

sed $'s/ones/two\'s/' <<< 'ones thing'
John C
  • 4,276
  • 2
  • 17
  • 28
  • 4
    The C-style `$'string'` is Bash-specific, so it's not portable to POSIX shell. – tripleee Dec 09 '16 at 13:31
  • 1
    It's not `bash` specific. It's also available in `ksh` and `zsh`, but yes, it's an extension to POSIX, which is fine if you aren't writing a portable script. The only downside is that you have to escape any other backslashes you use as well. – dannyw Jan 08 '20 at 05:40
  • *The best way* clearly depend on your use case! There is not only one best way! Have a look at [my answer](https://stackoverflow.com/a/66703200/1765658) – F. Hauri - Give Up GitHub Jan 04 '23 at 10:28
8

Just use double quotes on the outside of the sed command.

$ sed "s/ones/one's/" <<< 'ones thing'
one's thing

It works with files too.

$ echo 'ones thing' > testfile
$ sed -i "s/ones/one's/" testfile
$ cat testfile
one's thing

If you have single and double quotes inside the string, that's ok too. Just escape the double quotes.

For example, this file contains a string with both single and double quotes. I'll use sed to add a single quote and remove some double quotes.

$ cat testfile
"it's more than ones thing"
$ sed -i "s/\"it's more than ones thing\"/it's more than one's thing/" testfile 
$ cat testfile 
it's more than one's thing
2

This is kind of absurd but I couldn't get \' in sed 's/ones/one\'s/' to work. I was looking this up to make a shell script that will automatically add import 'hammerjs'; to my src/main.ts file with Angular.

What I did get to work is this:

apost=\'
sed -i '' '/environments/a\
import '$apost'hammerjs'$apost';' src/main.ts

So for the example above, it would be:

apost=\'
sed 's/ones/one'$apost's/'

I have no idea why \' wouldn't work by itself, but there it is.

Ambrown
  • 361
  • 2
  • 8
  • 5
    It's because ["A single quote may not occur between single quotes, even when preceded by a backslash."](https://www.gnu.org/software/bash/manual/bashref.html#Single-Quotes) The [answer above by Thomas Bratt](https://stackoverflow.com/questions/24509214/how-to-escape-single-quote-in-sed/24509305#24509305) explains the proper workaround. – wisbucky May 08 '19 at 00:35
  • Yes or replace `$apost` by `\'`: `sed 's/ones/one'\''s/'` will work too. – F. Hauri - Give Up GitHub Jan 04 '23 at 10:26
0

Some escapes on AppleMacOSX terminals fail so:

sed 's|ones|one'$(echo -e "\x27")'s|1'  <<<'ones thing'
Benjamin Loison
  • 3,782
  • 4
  • 16
  • 33
PaSe
  • 93
  • 1
  • 1
  • `echo -e` isn't properly portable either, and running a subprocess just to get it to print a literal single quote is silly. The simple expression `sed 's|ones|one'\''s|'` would work just as well. That's `s|ones|one` in single quotes, followed by a literal escaped single quote `\'` followed by `|s` in single quotes. (The trailing `1` is completely redundant.) – tripleee Jan 19 '23 at 12:38
-1

use an alternative string seperator like ":" to avoid confusion with different slashes

sed "s:ones:one's:" <<< 'ones thing'

or if you wish to highligh the single quote

sed "s:ones:one\'s:" <<< 'ones thing'

both return

one's thing
Benjamin Loison
  • 3,782
  • 4
  • 16
  • 33
  • That's not the issue here at all; the OP's code has no slashes. This is a good answer to a completely different question which has however been answered hundreds of times before on this site. – tripleee Mar 17 '21 at 07:37