Escape a single quote in Bash

'it'\''s'

'it'\''s' is how to write it’s in single quotes in Bash or any POSIX shell. Nothing is special between single quotes, not even a backslash, so a single quote can’t appear there at all. Instead, end the quoted part, add an escaped quote \', and start a new quoted part; the shell joins the three pieces into one word:

echo 'it'\''s'
# it's

The tool below writes the same 'it'\''s' for it's. Give it longer text and it quotes the whole thing: it's $HOME becomes 'it'\''s $HOME', with $HOME left unexpanded.

A backslash inside the quotes doesn’t work. Bash reads on to the end of the script looking for the closing quote:

echo 'it\'s'
# b2.sh: line 1: unexpected EOF while looking for matching `''

Double quotes take a single quote as it is, "it's", but inside them $, backticks and \ are still special, so they’re safe only for text you wrote yourself.

$‘…’ quoting

Bash, ksh and zsh also have ANSI-C quoting, $'…', where backslash escapes work as in C, \' included:

echo $'it\'s\tdone'
# it's	done

POSIX added it in its 2024 edition, so an older /bin/sh may not have it.

Let the shell quote it

When the text is in a variable, Bash can quote it for you. printf %q puts a backslash before each special character, and ${var@Q}, from Bash 4.4, wraps the value in single quotes:

msg="it's \$HOME"
printf '%q\n' "$msg"
echo "${msg@Q}"
it\'s\ \$HOME
'it'\''s $HOME'

/bin/bash on macOS is 3.2, where ${msg@Q} fails with bad substitution; printf %q works there. The tool’s Unescape reads both forms back to it's $HOME.

This matters when a command string goes through a second shell, as with bash -c, ssh host or eval. The outer shell removes one layer of quoting, so the inner one sees the bare text:

msg="it's \$HOME"
bash -c "echo $msg"
# bash: -c: line 1: unexpected EOF while looking for matching `''
bash -c "echo $(printf '%q' "$msg")"
# it's $HOME

Python’s shlex.quote

From Python, shlex.quote quotes for any POSIX shell. It closes and reopens too, but puts the quote in double quotes instead of escaping it:

import shlex, subprocess

msg = "it's $HOME"
print(shlex.quote(msg))
print(shlex.join(["echo", msg]))
subprocess.run(f"echo {shlex.quote(msg)}", shell=True)
subprocess.run(["echo", msg])
'it'"'"'s $HOME'
echo 'it'"'"'s $HOME'
it's $HOME
it's $HOME

The last call needs no quoting at all: a list of arguments skips the shell, which makes it the safer default. shlex.join needs Python 3.8 or later.

Try it in the String Escape & Unescape

4 of up to 100,000 characters

Wraps the text in single quotes; an inner ' is written as '\''.

Result
'it'\''s'

Runs in your browser. Nothing you enter is sent anywhere.