As tripleee points out in comments on the question, the best approach in this particular scenario is to use a double-quoted string, in which you can embed both variable references (e.g., $i
) and single quotes as-is; e.g.: z="'$i.ala.r$x.sph $i .ala.r$y.sph'"
This answer focuses on the various approaches to producing / embedding literal '
chars. in strings, starting with the OP's misconception.
Your use of '\''
suggests that you're confused by the workaround that is commonly used to "embed" a single quote in an overall single-quoted string, which is not what your code does on the z=...
line, because it starts with '\''
.
If we simplify your command, we get:
echo '\''$i
which is a syntax error, because to Bash the single quotes are unbalanced, because '\'
by itself is considered a complete single-quoted string containing literal \
, followed by the opening '
of a second single-quoted string, which is never closed.
Again it's worth noting that "'$i"
is the best solution to this specific problem: the '
can be embedded as-is, and including variable reference $i
inside the double-quoted string protects its value from potentially unwanted word-splitting and filename expansion (globbing).
POSIX-like shells provide NO way to embed single quotes inside a single-quoted string - not even with escaping. Hence, the \
in '\'
is simply treated as a literal (see below for a workaround).
The rest of this answer shows all approaches to producing a literal '
, both inside and outside quoted strings.
To create a single quotation mark outside of a quoted string, simply use \'
:
$ echo I am 6\' tall.
I am 6' tall.
This quotes (escapes) the individual '
character only, using \
.
But note that tokens placed outside the context of a single- or double-quoted string on a command line are subject to word-splitting and filename expansion (globbing).
To use a single quote inside a double-quoted string, use it as-is (no escaping needed):
$ echo "I am 6' tall."
I am 6' tall.
This is the best choice if you also want to embed variable references (e.g., $i
) or commands (via command substitutions, $(...)
) in your string (you can suppress interpolation by escaping $
as \$
).
To use a single quote inside a single-quoted string (in which no interpolations (expansions) are performed by design), you must use a workaround:
$ echo 'I am 6'\'' tall.'
I am 6' tall.
The workaround is necessitated by single-quoted strings not supporting embedded single quotes at all; the '\''
part only makes sense "inside" a single-quoted string in that:
- the leading
'
terminates the single-quoted string so far
- the
\'
then produces a '
literal individually escaped with \
outside the context of a quoted string.
- the trailing
'
then "restarts" the remainder of the single-quoted string.
In other words: While you cannot directly embed a single quote, you can break the single-quoted string into multiple pieces, insert individually \
-escaped '
instances outside the single-quoted string as needed, and let Bash's string concatenation (which automatically joins directly adjacent string) piece it all back together to form a single string.
chepner points out in a comment that you can alternatively use a here-document with a quoted opening delimiter, which acts like a single-quoted string while allowing embedding of '
chars:
read -r var <<'EOF' # quoted delimiter -> like a '...' string, but ' can be embedded
I am 6' tall.
EOF
With an unquoted opening delimiter, the here-document acts like a double-quoted string, which, just like the latter, also allows embedding '
, while also supporting expansions:
read -r var <<EOF # unquoted delimiter -> like a "..." string
$USER is 6' tall.
EOF
Finally, if remaining POSIX-compliant is not a must, you can use an ANSI C-quoted string string, which allows embedding single quotes with \'
;
note that such strings interpret control-character escape sequences such as \n
, but otherwise, like a normal single-quoted string, do not perform interpolation of variable references or command substitutions:
$ echo $'I am 6\' tall.'
I am 6' tall.