Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I want to embed a single quote in a string

Tags:

linux

bash

sh

Usually, in order to embed a quotation mark in a string, \ (backslash) is used.

Does a backslash have a different meaning in a Bash script?

My code below isn't working: the quotation mark wasn't included, and the following errors were reported:

recursive_merge.sh: line 7: unexpected EOF while looking for matching `''
recursive_merge.sh: line 14: syntax error: unexpected end of file

I have no explanation. Line 14 doesn't even exist.

 #!/bin/bash
#############this file should be in the directory directly upper than p0x. sphnum.txt should also be at the same directory
for i in 02 03 04 05 06 07 09 10 11 12 13 14 15 16 17 20 21 22 23 24 25; do
 x=$(grep $i sphnum.txt |cut -c5-6)
 y=$(grep $i sphnum.txt |cut -c8-9)
 z=$(echo '\''$i'.ala.r'$x'.sph '$i'.ala.r'$y'.sph\'')
 w=$(echo $i'.ala.r'$x'r'$y'.sph')
 echo $z
 echo $w
 cd p$i/spheres.10_2_75/sph/
 /project/Biogroup/Software/Docking/MergeSpheres.pl -s $z -o $w -n 500 &
 cd ../../../
done
like image 870
SIMONSON92 Avatar asked Sep 11 '25 20:09

SIMONSON92


1 Answers

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.
like image 145
mklement0 Avatar answered Sep 14 '25 14:09

mklement0