5

I always thought that bash treats backslashes the same when using without or with double quotes, but I was wrong:

[user@linux ~]$ echo "foo \ "
foo \
[user@linux ~]$ echo foo \ # Space after \
foo

So I thought backslashes are always printed, when using double quotes, but:

[user@linux ~]$ echo "foo \" "
foo "
[user@linux ~]$ echo "foo \\ "
foo \

Why is the backslash in the first code line shown?

8

Section 3.1.2.3 Double Quotes of the GNU Bash manual says:

The backslash retains its special meaning only when followed by one of the following characters: ‘$’, ‘`’, ‘"’, ‘\’, or newline. Within double quotes, backslashes that are followed by one of these characters are removed. Backslashes preceding characters without a special meaning are left unmodified. A double quote may be quoted within double quotes by preceding it with a backslash. If enabled, history expansion will be performed unless an ‘!’ appearing in double quotes is escaped using a backslash. The backslash preceding the ‘!’ is not removed.

Thus \ in double quotes is treated differently both from \ in single quotes and \ outside quotes. It is treated literally except when it is in a position to cause a character to be treated literally that could otherwise have special meaning in double quotes.

Note that sequences like \', \?, and \* are treated literally and the backslash is not removed, because ', ? and * already have no special meaning when enclosed in double quotes.

5

Backslash is interpreted differently according context:

  • Within double quotes (your first example):

    The backslash  retains its special meaning  only when followed
    by one of the following characters: $, `, ", \, or <newline>.
    
  • Without quotes (your second example):

    A  non-quoted  backslash  (\)  is the  escape  character.   It
    preserves  the  literal  value  of  the  next  character  that
    follows,  with the  exception of  <newline>.  If  a \<newline>
    pair  appears, and  the backslash  is not  itself quoted,  the
    \<newline> is treated  as a line continuation (that  is, it is
    removed from the input stream and effectively ignored).
    
  • Using the construct $'....', where you can use inside the quote the standard backspace character, nearly as in C. e.g. \n, \t, etc.

  • Using backquotes:

    When  the old-style  backquote form  of substitution  is used,
    backslash retains its literal  meaning except when followed by
    $, `, or \.
    

Source of quotes: bash manual

  • Some of the text that you quoted has been misinterpreted during the conversion from markdown, resulting in missing words and characters. – dhag Oct 17 '17 at 14:50
  • In this case, I would just quote the manpage as code, avoiding this whole class of issues. (There is some mangling left, I will submit an edit to fix this.) – dhag Oct 17 '17 at 15:14
  • @dhag Although I don't think manpage quotes usually look better as code, I'm glad you've re-edited it, because I now see that I introduced mistakes in my own edit (I turned \<newline> into <newline>) which harmed the post, and which your edit fixes. Sorry about that, and thanks! – Eliah Kagan Oct 17 '17 at 16:15
  • @EliahKagan: No problem. I agree that code isn't the proper way to quote text, but it's sometimes the easiest way to avoid breaking anything :). – dhag Oct 17 '17 at 18:13
0

Here is a 'complicated for the sake of understanding' example. Hopefully it'll be helpful for anyone else trying to understand qutoes and backslashes.

In the example here, I want to repeat the pattern 3 times.

>~# echo 'ABC\n\t'
ABC\n\t

Using single quotes, it is fairly straightforward:

>~# echo 'ABC\n\t' | sed -e 's#ABC\\n\\t#ABC\\n\\tABC\\n\\tABC\\n\\t#'
                                  ↑  ↑      ↑        ↑  ↑     ↑  ↑
                    # These backslashes escaped by sed
ABC\n\tABC\n\tABC\n\t

Here is the way to do it using double quotes: (again, complicated just for the sake of understanding)

>~# echo 'ABC\n\t' | sed -e "s#ABC\\\n\\\t#$(printf '%0.sABC\\\\n\\\\t' $(seq 1 3))#"
                                  ↑   ↑                     ↑ ↑  ↑ ↑
            # These backslashes are removed in double quotes. Showing intermediate stage:

>~# echo 'ABC\n\t' | sed -e "s#ABC\\n\\t#$(printf '%0.sABC\\n\\t' $(seq 1 3))#"

                # Expanding printf results in:

>~# echo 'ABC\n\t' | sed -e 's#ABC\\n\\t#ABC\\n\\tABC\\n\\tABC\\n\\t#'

ABC\n\tABC\n\tABC\n\t

Just to play around and master quotes and backslashes, replace the single quotes around printf with double quotes.

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.