2

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
mklement0
  • 382,024
  • 64
  • 607
  • 775
SIMONSON92
  • 73
  • 6
  • 5
    Use [\[ shellcheck \]](http://shellcheck.net) – sjsam Jul 27 '16 at 02:35
  • @tripleee: While the [linked question](http://stackoverflow.com/questions/10067266/when-to-wrap-quotes-around-a-variable?noredirect=1&lq=1) is generally related, neither it nor its answers address _embedding_ single quotes inside (single-quoted) strings or producing _stand-alone_ single-quote literals, which is the focus of _this_ question. – mklement0 Jul 27 '16 at 04:29
  • @mklement0 Actually, http://stackoverflow.com/a/27701642/874188 suggests using double quotes around the single quotes when you want a literal single quote. But I am fine with leaving this question open as well. (For context, for future readers, I previously marked this as a duplicate, but it was reverted.) – tripleee Jul 27 '16 at 04:33
  • 1
    You should be using `echo "$variable"` with double quotes throughout; your diagnostics are off because the lack of quoting effectively makes the shell evaluate the variable again -- you basically don't see what you're doing. Again, the [duplicate I proposed](http://stackoverflow.com/questions/10067266/when-to-wrap-quotes-around-a-variable) covers this in much more detail. – tripleee Jul 27 '16 at 04:36
  • 1
    And of course, the [useless use of `echo` in backticks](http://www.iki.fi/era/unix/award.html#echo) probably throws you off some more (unless the purpose of that is to experiment with how command substitution complicates matters even further). – tripleee Jul 27 '16 at 04:37
  • @tripleee: Thanks; all good points; I've added a preamble to my answer. – mklement0 Jul 27 '16 at 04:44
  • Perhaps a better duplicate: http://stackoverflow.com/questions/1250079/how-to-escape-single-quotes-within-single-quoted-strings though I'll leave it to the community to decide now, since my duplicate already got rejected once. – tripleee Jul 27 '16 at 04:59
  • Though I'm guessing this is really properly a duplicate of http://stackoverflow.com/questions/38572630/bash-function-for-escaping-spaces-in-filenames-before-opening-them/38572764#38572764 -- if you are trying to put a literal quote but the file name you are trying to access does not actually contain a literal quote, you need to understand at what level the quotes are useful and relevant, and how the shell peels them off. – tripleee Jul 27 '16 at 05:02
  • @triplee: I agree that http://stackoverflow.com/questions/1250079/how-to-escape-single-quotes-within-single-quoted-strings comes closest as a duplicate; to me this answer still has a distinct angle, though it's hard to address all its layers without losing focus. No duplicate candidate juxtaposes all approaches to embedding a single quote, as far as I can tell (which is admittedly the thing _I_ chose to focus on). If you feel strong enough about one of your duplicate candidates, please go ahead. – mklement0 Jul 27 '16 at 05:22
  • 1
    My strongest suspicion is in the last comment; the OP is mistaken, and doesn't actually need a literal single quote. But this is qualified guesswork, so I'm simply offering this for the OP to decide. – tripleee Jul 27 '16 at 05:23
  • 1
    `foo="'a b'"; echo $foo` is not the same as `echo 'a b'`, if that is why you are trying to put single quotes in the value. The former passes two arguments, `'a` and `b'` to `echo`, while the latter passes a single argument `a b`. – chepner Jul 27 '16 at 13:31
  • Thanks dudes! It helped! – SIMONSON92 Jul 28 '16 at 01:02

1 Answers1

5

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.
Community
  • 1
  • 1
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 1
    You can include a single quote if you count a quoted here-doc delimiter as a single-quoted string. (`IFS= read -r a <<'EOF' '$a EOF`--apologies for the formatting--is a legitimate, albeit verbose, alternative to simple assignment.) – chepner Jul 27 '16 at 13:29
  • Thanks, @chepner. I've added your suggestion to the answer. – mklement0 Jul 27 '16 at 16:58
  • Thank you so much guys. You are so kind even to a novice like me – SIMONSON92 Jul 28 '16 at 01:01