3

Per the POSIX Shell Command Language Page:

\

The <backslash> shall retain its special meaning as an escape character (see Escape Character (Backslash)) only when followed by one of the following characters when considered special:

$ ` " \ <newline>

This would seem to imply that escaping these five characters with a backslash would not have the effect of escaping them and having them be treated literally if they are not "special".

Am I interpreting this correctly, and if so, are there cases where escaping one of these five special characters with a \ would not have the intended effect of escaping it?

  • It seems to imply to me that there might be times where both the backslash and the $ were to be included literally, not that the $ might retain a special meaning despite a preceding backslash. Is that what you read it as, or not? – Michael Homer Jan 6 at 21:13
  • 1
    The meaning is that for example in " dog \n cat" the \n is 2 characters, as n is not a dollar, backquote, .... The point is that backslash normally quotes everything, but inside double quotes it only quotes the 5 listed characters. – icarus Jan 6 at 21:27
  • The solution in that case would probably be to un-mangle the question and ask another question that said what you wanted. – Michael Homer Jan 7 at 3:23
1

@MichaelHomer explains it very well. Let's try a few practical cases with PS1='\$ ':

$ echo "$ at start"
$ at start
$ echo "at end $"
at end $
$ echo "$before"

$ echo "after$"
after$

So $ is only "special" before a word, making it a parameter substitution. What happens if we put a backslash before all of them?

$ echo "\$ at start"
$ at start
$ echo "at end \$"
at end $
$ echo "\$before"
$before
$ echo "after\$"
after$

Only the "special" line changes - the dollar sign is now considered literal. It was always considered literal. What happens with other characters?

$ echo "\ at start"
\ at start
$ echo "at end \"
> ^C
$ echo "\before"
\before
$ echo "after\"
> ^C

So backslash is just another literal character before a non-special character. (^C is where I had to cancel the command line because the quote character had been escaped.)

1

A character, say $, has a special meaning and is considered special when it has some impact other than being a literal part of data. In $x, $ has a special meaning introducing parameter expansion.

What this passage is saying is that the backslash has its escape-character meaning only when it precedes a one of these characters with a special meaning. Ordinarily, the backslash has broader escaping meaning:

A <backslash> that is not quoted shall preserve the literal value of the following character, with the exception of a <newline>

For example, "\$x" is the string "$x", while "a\ b" is the string "a\ b", because the backslash in the second case precedes an unlisted character and so has no special meaning. Outside double quotes, however, a\ b is the string "a b", with the backslash causing the space to be included literally, and the backslash itself removed.

The passage you quoted isn't saying that sometimes the characters keep their special meaning despite being escaped, but rather that the backslash has no special meaning unless it would be impacting one of them.


There is a potential dangling modifier here: are the characters considered special, or the backslash?

There are some potential cases where some of those characters inside double quotes may not have a special meaning - most obviously within embedded expansions described in the immediately-preceding points to the one you quoted, but also in the delimiter of a here-document. Embedded expansions have their own quoting rules, however, as do here-document delimiters, so it's not clear to me that it can practically arise. If it's the backslash, all it says is that a double backslash doesn't escape anything.

The best case I have for where, if it is limiting the characters, it might come up is here-document delimiters:

cat <<"A$B"
A$B
cat <<"A\$B"
A$B

Both of those do the same thing on all my shells. Arguably the $ is not special, since it was included in the delimiter the first time, and so the \ inside double quotes should not have escaped it the second time and should have been literally included. I don't think it's clear that this is required behaviour but it does seem consistent with the letter of the law.

For embedded expansions they either disavow any effect from the quotes (both kinds of $(...)) or have both their own quoting rules and no unique way to have something be quoted (all kinds of ${...} and ` ... `), and I haven't managed to construct something that clearly should have a non-special version of one of those characters and a non-special backslash before it.

I suspect the bolded text is currently redundant. The potential dangling modifier at the least makes it ambiguous, and perhaps this is a phrasing bug to file for the errata or next update.

  • I actually made that text bold to put emphasis on what confused me- the documentation itself does not use bold letters in that way – Harold Fischer Jan 6 at 22:14
  • Yeah, I know. Basically, I think it's redundant: I can't construct a case that definitively 1) includes the characters inside double quotes 2) without a special meaning 3) where a preceding backslash should have no impact. $(...) explicitly disavows any impact from quoting; ${...} has its own, bizarre, quoting rules, and the characters are always special; bare $ in quotes falls into that "unspecified" trap. The only clear contender is here-document delimiters - every shell I have treats `` $ ` \ `` literally, but also lets you escape them and it delegates straight to quote removal. – Michael Homer Jan 6 at 22:21
  • It's possible that letter-of-the-law cat <<"A\$B" should have the literal delimiter A\$B, since cat <<"A$B" has delimiter A$B, but it's arguable. – Michael Homer Jan 6 at 22:24
  • Does echo "$" invoke unspecified behavior? – Harold Fischer Jan 7 at 2:07
  • It does seem to. – Michael Homer Jan 7 at 2:22
0

Lets try to simplify.
The text, as written is:

The <backslash> shall retain its special meaning as an escape character (see Escape Character (Backslash)) only when followed by one of the following characters when considered special:

We can convert some parts of it:

  1. The <backslash> ==> The B

  2. ... shall retain its special meaning as an escape character
    ... \__________/------------------------\__________________/
    ==> still is -------------------------------- an escape character
    ==> still is an escape

    As it was in un-quoted strings.

  3. ... only

  4. ... when followed by one of the following characters ==> A B before [$`"\NL]

  5. ... when considered special

Then, 1,2,and 4 read as: B still is an escape before [$`"\NL]

  • The controversial part is: when considered special

    What is being considered special ?

    I believe that it is >> "the characters" << . As written:

    one of the following characters when considered special:

    Q: For example: when is a " special (inside double quotes)?

    A: Always (not considering nested structures like echo "$(sed 's/["]//' file)").

    So, a backslash will always quote a ": echo "a\"b\"b\"" (again: no nested structures).

  • Then, 1,2,3,4 and 5 should read as:

    B still is an escape only before special [$`"\NL]

Then, the answer to your question:

are there cases where \ fails to escape $, ```, ", \ or <newline>?

Is: YES, when the characters [$`"\NL] are not special.

They (the characters) may be not special inside nested structures (for example) yet inside quotes.

  • 1
    That's also the only explanation I can think of. But still, that specification would still be broken in that NL is not special inside double quote (when not part of expansions), but \NL still has its special line-continuation meaning. I think we should bring it to the austin-group for clarification. – Stéphane Chazelas Jan 9 at 9:42
  • Another possible explanation is the interaction with the `...` form or command substitution. For instance $HOME is expanded in echo `echo "\$HOME"`. So maybe it's about backslash not being special there (I doubt it though). – Stéphane Chazelas Jan 9 at 9:47
  • In 2.2.1 the spec states that: The <backslash> and <newline> shall be removed before splitting the input into tokens.. Also repeated at 2.10.2 Also note that line joining is done before tokenization, as described in Escape Character (Backslash),. So, it follows that the shell doesn't see the line-continuation for tokenization. Maybe that's the reason for the slip. But yes, it looks like an slip about the NL. – Isaac Jan 9 at 10:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.