Guide to Unix/Explanations/Quoting and Filename Expansion

Special characters and substitution


The shell recognizes several special characters. The following are the special characters:

  • \ (backslash)
  • " (double quote)
  • ' (single quote)
  • # {number sign, pound sign, or hash)
  • $ (dollar sign)
  • ` (tick)
  • ~ (tilde)
  • { and } (braces or curly brackets)
  • ( and ) (parentheses)
  • * (asterisk, star or splat)
  • ? (question mark)
  • < (less than sign)
  • > (greater than sign)
  • & (ampersand)
  • | (pipe)
  • ; (semicolon)
  • ! (exclamation point or bang)

They are all special characters in the Bourne shell, except for the exclamation point. However, many Bourne and non-Bourne shells also make special the exclamation point. When the shell sees special characters, it does something more complex than simply running the command that you typed.

Some special characters trigger substitution, when parts of the command are replaced with other text. One common form of substitution is filename expansion, which saves you work when typing longer filenames and lists of filenames.

To test substitution, we need the echo command. This command simply echoes its arguments (including any changes made to the arguments by the shell). All options except "-n" are ignored.

$ echo -lnQ arg1 arg2 arg3
-lnQ arg1 arg2 arg3



Quoting is used to preserve the literal meaning of special characters.

Here is an example of several types of quoting, which will be referred to in the rest of this section (there are many unnecessary things in this which you should find after reading this section, but are used for the sake of example):

$ echo There is \"a small possibility\" that '/etc/*tab' are " not " text and a backslash will not be printed after this. \\
There is "a small possibility" that /etc/*tab are  not  text and a backslash will not be printed after this. \



A backslash (\) simply stops the shell from thinking that certain characters are special. In the example above, it was used to print literally the doublequote character.

To print a backslash, use two backslashes in a row.

Now commands that want special shell characters for input will work.

Paired quoting characters


Paired characters affect whatever is between them.

Single quotes


Single quotes prevent all expansion, thus preserving the literal meaning for all chars.

In the example, single quotes were used to prevent the * from expanding.

Single quotes can't be used within single quotes. Any 2nd single quote always terminates the 1st, whereas a 3rd single quote begins the next pair.

Double quotes


Double quotes are like single quotes, but don't preserve the literal meaning of $, \ when followed by a dollar sign, tick, double quote, or backslash, and `.

In the example, double quotes were used to preserve the literal meaning of spaces.

Filename expansion


Filename expansion uses the following characters to avoid typing long lists of files:

* ? { }

* and ?


The shell globbing characters of * and ? are used to form patterns. The shell searches for existing files that match the patterns and does a subsitution.

  • * matches 0 or more characters, except /
  • ? matches any 1 character except /

When more than one file is matched, the files are separated by spaces, as separate arguments.

For example, /etc/ss* means all of the files inside the /etc directory which begin with the letters ss. The echo command demonstrates the substitution. The results may differ on your system, depending on what files you have.

$ echo /etc/ss*
/etc/ssh /etc/ssl

The echo command did this because it thinks that you ran echo /etc/ssh /etc/ssl. The shell substituted those names for /etc/ss*. Though /etc/ssh/ssh_config exists on many systems, it appeared not above, because * never matches /.

Now here is something more useful. We will use substitution with a command other than "echo". We will combine filename expansion with the ls command.

$ ls /etc/ss*
ssh_config                 ssh_host_key     
ssh_host_dsa_key            sshd_config       ssh_host_rsa_key

lib          openssl.cnf  private      x509v3.cnf

Notice how the * reduced extra typing. If we did ls /etc/s*, we would probably further reduce the amount the user needs to type.

Here is an example of the ? character at work:

$ ls /etc/ssh/ssh_host_???_key
/etc/ssh/ssh_host_dsa_key  /etc/ssh/ssh_host_rsa_key

When expansion fails


Sometimes, when using * or ?, no files are found. In this case, the shell does not give an error; it simply does no substitution. Suppose that in the machine on the example above, we make a mistake and typed /etc/sss* which matches nothing. Then the shell would do no substitution:

$ echo /etc/sss*

Curly brackets expansion


The curly brackets help when typing several similar arguments, especially filenames. The filenames do not need to actually exist. Example:

$ echo /etc/ss{h,l,ssnakes}
/etc/ssh /etc/ssl /etc/ssssnakes

They are very useful for long lists of files in the same directories:

$ echo /bin/{ls,mv,cp} /sbin/{halt,reboot}
/bin/ls /bin/mv /bin/cp /sbin/halt /sbin/reboot

You can also use them to print the alphabet (or numbers):

$ echo {z..a}
z y x w v u t s r q p o n m l k j i h g f e d c b a