18

Many questions like 'How to type the double-quote char (")?' are being asked, and we don't want to clutter our community with the same answer (Type it as \" if not enclosed in 's, " if enclosed in 's.) So, the question is here.

You can't type special chars into a terminal like normal ones, e.g. this command will fail:

echo Updates (11)

So, how to type in these chars in the terminal as if they were normal ones?

!#$^&*?[](){}<>~;'"\|<space><tab><newline>
EKons
  • 944

2 Answers2

37

That very much depends on the shell. Check your shell manual for details.

Also note that some characters are only special in some contexts. For instance, in most shells,* and ? are only special in list contexts, in POSIX or csh-like shells, ~ is only special at the beginning of a word or following some characters like :. Same for = in zsh. In some shells, [ is only special when matched (with some restrictions) by a ].

In some shells like bash or yash, special characters like blank token delimiters also vary with the locale.

The quoting operators (to remove the special meaning of those characters) also vary greatly between shells.

Bourne-like shells

A summary for Bourne-like shells (that is the shells that have been known to be called sh on some system or another since the 80s):

Bourne shell

Special characters:

  • "'&|;()^`<>$, space, newline and tab are special in simple command lines when not quoted.
  • # (except in early version) is special at the beginning of a line or following an unquoted space, tab or &|()^<>;`.
  • { and } are only special in that they are shell keywords (so only words in command position).
  • *?[ are special as globbing operators, so only in list contexts. In the case of [, it's [...] that is the globbing operator, either [ or ] only need to be quoted to remove the special meaning.
  • = is special when in contexts where it's treated as an assignment operator. That is, in a simple command, for all words that do not follow an argument (except after set -k).

Quoting operators

  • \ quotes all special characters except newline (\<newline> is a way to continue a long logical line onto the next physical line, so that sequence is removed). Note that backticks add extra complexity as within them, \ is used first to escape the closing backtick and help the parser. Inside double quotes, \ may only be used to escape itself, ", $ and ` (\<newline> is still a line-continuation). Inside a here-document, same except for ". \ is the only way to escape characters inside here documents.
  • "..." double-quotes escape all characters but itself, \, $ and `.
  • '...' single quotes escape all characters but itself.

POSIX shells

POSIX shells behave mostly like the Bourne shell, except that:

ksh

like POSIX except that:

  • {string} is special if string contains an unquoted , (or .. in some cases and with some versions).
  • ksh93 has an additional special quoting operator: $'...' with complex rules. That operator is also found (with some variations) in bash, zsh, mksh and FreeBSD and busybox sh.
  • ksh93 also has a $"..." quoting operator that works like "..." except that the string is subject to localisation (could be configured so it translates to the language of the user). mksh ignores the $ in $"...".
  • since ksh93r, ksh93 supports csh-style history expansion (not enabled by default) with -H / -o histexpand in interactive shells which makes ^ at the beginning of commands and ! special. ! is then special in some contexts (not when followed by space or TAB nor in here documents) and is not escaped by double quotes. Only backslash (not within double-quotes where \ removes ! its special meaning but is not otherwise removed) and single quotes escape it.

bash

like ksh93 but:

  • in single-byte character locales, all blank (according to the locale) characters are considered as delimiters (like space or tab). In effect, that means you should quote all bytes with the 8th bit set in case they may be a blank character in some locale.
  • csh history expansion is enabled by default in interactive instances, with the same notes as on ksh93 above except that in newer versions of bash, ! is also not special sometimes, when followed by a ".
  • like in csh, % at the start of a command is used to manipulate jobs. %1 puts job number one in foreground instead of running the %1 command. Same with %1 & to put it in background...

zsh

like ksh93 but:

  • same note as for bash for csh history expansion, except that backslash can be used to escape ! inside double quotes like in csh.
  • = is special as the first character of a word (=ls expands to /bin/ls).
  • same note as for bash about % in command position.
  • { and } can also open and close command groups when not delimited (as in {echo text} works like Bourne's { echo text;}).
  • except for [ alone, [ needs quoted even if not closed with a ].
  • With the extendedglob option enabled, #, ^ and ~ are globbing operators.
  • With the braceccl option, {non-empty-string} is special.
  • $"..." is not supported.
  • as a special quirk, ? is not special when following a % (even quoted or expanded) at the start of a word (to allow the %?name job specification)
  • a rcquotes option (not enabled by default) allows one to enter single quotes as '' inside single quotes à la rc (see below).

yash

like POSIX except that.

  • all blank characters are considered as delimiters.
  • With the brace-expand option, implements zsh-style brace expansion.
  • same note as for bash and zsh about % in command position (except when in POSIX mode).

For all shells, there are some special contexts where quoting works differently. We've already mentioned here documents and backticks, but there's also [[...]] in ksh and a few other shells, POSIX $((...)), case constructs...

Also note that quoting can have other side-effects when it comes to expansions (with double-quotes), or when applied to here document delimiters. It also disables reserved words and affects alias expansion.

Summary

In Bourne-like shells, !#$^&*?[(){}<>~;'"`|=, SPC, TAB, NEWLINE and some bytes with the 8th bit set are or may be special (at least in some contexts).

To remove the special meaning so they be treated literally, you use quoting.

Use:

  • '...' to remove the special meaning of every character:

    printf '%s\n' '\/\/ Those $quoted$ strings are passed literally as
    single arguments (without the enclosing quotes) to `printf`'
    
  • \ to remove the special meaning of one character only:

    printf '<%s>\n' foo bar\ baz #comment
    

    Above, only the space character preceded by a \ is passed literally to printf. The other ones are treated by the shell as token delimiters.

  • use "..." to quote characters while still allowing parameter expansion ($var, $#, ${foo#bar}...), arithmetic expansion ($((1+1)), also $[1+1] in some shells) and command substitution ($(...) or the old form `...`. Actually, most of the time, you do want to put those expansions inside double quotes in any case. You can use \ within "..." to remove the special meaning of the characters that are still special (but only them).

  • if the string contains ' character, you can still use '...' for the rest and use other quoting mechanisms that can quote ' like "'" or \' or (where available) $'\'':

    echo 'This is "tricky", isn'\''t it?'
    
  • Use the modern $(...) form of command substitution. Only use the old `...` for compatibility with the Bourne shell, that is, for very old systems, and only in variable assignments, as in don't use:

    echo "`echo "foo bar"`"
    

    Which won't work with the Bourne shell or AT&T versions of ksh. Or:

    echo "`echo \"foo bar\"`"
    

    Which will work with Bourne and AT&T ksh, but not with yash (2020 edit: only in version 2.41 and earlier though, it's since been changed in 2.42 / bug report / commit), but use:

    var=`echo "foo bar"`; echo "$var"
    

    which will work with all.

    Nesting them portably with double quotes is also impossible, so again, use variables. Also beware of the special backslash processing:

    var=`printf '%s\n' '\\'`
    

    Will store only one backslash inside $var, because there's an extra level of backslash processing (for \, `, and $ (and also " when quoted except in yash)) within backticks so you need either

    var=`printf '%s\n' '\\\\'`
    

    or

    var=`printf '%s\n' '\\\'
    

    instead.

Csh family

csh and tcsh have a significantly different syntax, though there is still a lot in common with the Bourne shell as they share a common heritage.

Special characters:

  • "'&|;()^`<>$, space, newline and tab are special everywhere when not quoted.
  • # (csh is the shell that introduced # as the comment leader) is special at the beginning of a script or following an unquoted space, tab or newline.
  • *?[ are special as globbing operators so in list contexts
  • {anything} is special except for the special case of a standalone {} (csh is the shell that introduced brace expansion).
  • ! and ^ are special as part of history expansion (again, a csh invention), and quoting rules are special.
  • ~ (tilde expansion also a csh invention) is special in some contexts.
  • Like in bash, zsh, yash, % in command position is used to manipulate jobs (again a csh invention).

Quoting operators

They are the same as for the Bourne shell, but the behaviour differs. tcsh behaves like csh from the syntax point of view, you'll find that many versions of csh have nasty bugs. Get the latest version of tcsh to get a roughly working version of csh.

  • \ escapes a single character except newline (same as for the Bourne shell). It's the only quoting operator that can escape !. \<newline> doesn't escape it but transforms it from a command separator to a token separator (like space)
  • "..." escapes all characters except itself, $, `, newline and !. Contrary to the Bourne shell, you can't use \ to escape $ and ` inside "...", but you can use \ to escape ! or newline (but not itself except when before a ! or newline). A literal ! is "\!" and a literal \! is "\\!".
  • '...' escapes all characters except itself, ! and newline. Like for double quotes, ! and newline can be escaped with backslash.
  • command substitution is only via the `...` syntax and can hardly be used reliably.
  • variable substitution is also pretty badly designed and error prone. A $var:q operator helps to write more reliable code involving variables.

Summary

Stay away from csh if you can. If you can't use:

  • single quotes to quote most characters. ! and newline still need a \.
  • \ can escape most characters
  • "..." can allow some expansions within it, but that's pretty buggy if they embed newline and/or backslash characters, best may be to use single quotes only and $var:q for variable expansion. You'll need to use loops if you want to join elements of an array reliably.

rc family

rc is the plan9 shell. plan9 code has now been released as FLOSS and its user space software including rc been ported to Linux. A clone of rc for Unix was also written in the early 90s by Byron Rakitzis, and from which derived es and akanga.

That's a shell with a much cleaner and better syntax and the one everyone would be using if we weren't stuck with Bourne-like shells for backward compatibility.

rc/akanga

Special characters

  • #;&|^$=`'{}()<>, SPC, TAB and NEWLINE are always special when not quoted.
  • *?[ are globbing operators.

Quoting operator

'...' is the only quoting operator. A literal ' is written with '' within single quotes as in:

echo 'it''s so simple isn''t it?'

es

es could be seen as an experimental shell based on rc.

It has a few differences though. The one of interest for this Q/A is that \ is also a quoting operator (that quotes all special characters except newline) and can also be used to introduce escape sequences like \n for newline, \b for backslash...

fish

fish is a relative newcomer (circa 2005), is primarily intended for interactive use and also has a significantly different syntax from other shells.

special characters

  • "'\()$%{}^<>;&| always special when not quoted (note the % (for pid expansion) as a significant difference from other shells, and ` is not special)
  • # (comment) special when following unquoted space, tab, newline or ;&|^<>
  • *? (but not [...]) globbing operators

Quoting operators

  • \ quotes a single special character except newline, but beware it also doubles as a C escape sequence (\n, \b...) introducer. IOW, \n is not a quoted n but a newline.
  • "..." quotes everything but itself, $ and backslash and backslash can be used to escape those. \<newline> is a line continuation (removed) inside "...".
  • '...' quotes everything but itself and \, and you can use backslash to escape those.
  • I have included only the ones special in all contexts (so that c acts the same as \c, c does not output c: command not found on STDERR, etc.) And I'm talking about sh here. Also, remember that this is a "clean-up" question, i.e. it's here to cover all such characters, so 19+ questions won't have to be asked. The question was posted thanks to an incident that different questions are asked for different such characters, we surely want to clean up here! – EKons Jul 15 '16 at 15:10
  • Well, ?[ are globbing operators, but isn't special in all contexts, but * seems to be, because echo * badly echoes the contents of the current directory (not escaping anything). echo ? echoes a literal ? and echo [ echoes a literal [. Also, ] is a globbing oberator too. – EKons Jul 15 '16 at 15:37
  • 1
    @ΈρικΚωνσταντόπουλος, * as a glob expands to all non-hidden files, ? to non-hidden single-character files, [a-z] to files whose name is a single character between a and z and so on. When they don't match any file (like in your case for ?), depending on the shell, you get a no-match error or the pattern expands to itself. In any case, even on shell where they expand to themselves, they need quoted in case they may match a file. – Stéphane Chazelas Jul 15 '16 at 17:04
  • But, not as a glob, * still expands to something. – EKons Jul 15 '16 at 17:54
  • @ΈρικΚωνσταντόπουλος, * is like ?, if it doesn't match (for the case of * alone, that's when there are only hidden files in the current directory, for a* that's where there's no file whose name starts with a...), it either expands to itself (most Bourne-like shells), or raises a no-match error (csh, tcsh, fish (warning), zsh, bash -O failglob, early Unix shells), (or expands to nothing with the nullglob option of some shells or if there's another pattern that expands to something in csh, tcsh, zsh -o cshnullglob, early unix shells). – Stéphane Chazelas Jul 16 '16 at 06:40
  • I don't think you got what I'm saying there, or there's a language barrier; echo * doesn't echo a literal *, it echoes the directory's contents. Replacing * with one of ?[] doesn't do it. – EKons Jul 16 '16 at 12:18
  • @ΈρικΚωνσταντόπουλος. Try: mkdir dir; cd dir; echo *; touch x y; echo ? in bash/sh and zsh and re-read my comments after that. – Stéphane Chazelas Jul 16 '16 at 12:38
  • Seems legit.... – EKons Jul 16 '16 at 12:41
  • Hi guys, where does all this information comes from? Especially escaping in double quotes. Thanks! – Tim Bernikovich Feb 15 '19 at 16:57
  • @TimurBernikovich, you'll find most of that information in the manuals of the respective shells. – Stéphane Chazelas Feb 17 '19 at 14:47
  • re. yash and echo "\echo "foo bar"`"`, it seems to work with the yash on my Debian (Yet another shell, version 2.43). – ilkkachu Oct 01 '20 at 11:51
  • You're right. Looks like it changed in 2.42 not long after I posted that answer. See https://osdn.net/projects/yash/ticket/36278 – Stéphane Chazelas Oct 01 '20 at 13:04
  • Typos: 1) "bash abd zsh" should be "bash and zsh". 2) "that is to very old system" would read better as "that is, for very old systems" or even "i.e. for very old systems". 3) "litteral" should be "literal". – raf Nov 26 '23 at 13:27
  • Thanks @raf. All applied now. – Stéphane Chazelas Nov 26 '23 at 13:32
5

1. Escape

Escape all of these characters with a \, like this (does not work on newlines/carriage returns):

$ echo Use a \"\\\" symbol to escape characters.
Use a "\" symbol to escape characters.

2. Double-quote

Enclose the whole text in "s, like this:

$ var=variables;echo "Enclose text in \"s. You can also use $var in them. `echo Surprise!!!`"
Enclose text in "s. You can also use variables in them. Surprise!!!

3. Single-quote

Same as double-quote, but there is no special token.

$ proof=proveit;echo 'This should not read "proveit": $proof'
This should not read "proveit": $proof
EKons
  • 944
  • 1
    You're describing the behaviour of the the fish shell, not Bourne-like shells where the single quote quotes every character (backslash is not special within '...'). Note that in fish, % is also a special character. – Stéphane Chazelas Jul 15 '16 at 17:08
  • @StéphaneChazelas I don't know how fish works, but my experience is that, in sh, echo '\\' echoes \ and echo '\'' echoes '. – EKons Jul 15 '16 at 17:55
  • 1
    echo '\\' outputs \ because your echo expands ANSI C escape sequences (some echo implementations need echo -e '\\' for that). printf '%s\n' '\\' outputs \. – Stéphane Chazelas Jul 15 '16 at 18:01
  • Note that sh does not identify a particular shell, there are and have been a lot of different and often incompatible shells called sh. – Stéphane Chazelas Jul 15 '16 at 18:03
  • @StéphaneChazelas Oh okay, I will change that now. By the way, is \' a special token inside a single-quoted character sequence? – EKons Jul 15 '16 at 18:04
  • \' is not a special token either inside single quotes. There's no way to embed a ' inside single quotes. You need to close the single quotes and insert the ' with another quoting mechanism as in echo 'foo'"'"'bar' or echo 'foo'\''bar'. – Stéphane Chazelas Jul 15 '16 at 18:06
  • @StéphaneChazelas The latter is less confusing and more code-golf suitable I think. – EKons Jul 15 '16 at 18:09