11

Should we put file names in Bash in Quotes or Double quotes? What is the standard?

SRC=file

or

SRC='file'

or

SRC="file"

?

1
  • If the value for the variable is fixed (as in your example), you can statically (i.e.: when writing the script) whether you need quotes, and if so, which to use. Specifically you would not need quotes at all. However when the decision is dynamic (e.g.: SRC=$1) it depends on what $1 will contain. Usually you cannot trust the contents. The problem gets more complex is you reuse $SRC, like in FILE=$SRC. It can get tricky if $SRC contains double.quotes (").
    – U. Windl
    Nov 21 at 7:28

4 Answers 4

12

One thing to note about variable assignments is that they are a bit of a special case in shell syntax. From the Bash documentation, in 3.7.1 Simple Command Expansion:

The text after the ‘=’ in each variable assignment undergoes tilde expansion, parameter expansion, command substitution, arithmetic expansion, and quote removal before being assigned to the variable.

In general, however, tokens also undergo field splitting and filename expansion (see 3.5 Shell Expansions), but those are not performed during variable asisgnment.

This means that an unquoted $foo is treated differently in the following cases:

some-command $foo
bar=$foo

Let's say foo='/* a b c */'. (* a b c * is a perfectly valid name for a directory, so /* a b c */ is a perfectly valid path to a directory.) For some-command $foo, it first becomes as if you'd written:

some-command /* a b c */

And then is expanded by the shell to something like:

some-command /bin /boot ... a b c dir1/ dir2/ ...

But for bar=$foo, that's not the case. Neither field splitting nor filename expansion will be done, and it will remain as-is - bar will have the value /* a b c */. However, if you then do some-other-command $bar, then it will do field splitting and filename expansion.

In both cases, though, a quoted "$foo" will have the same behaviour:

some-command "$foo" # no field splitting, no filename expansion
bar="$foo"          # equivalent to bar=$foo

Some rules of thumb:

  1. If your value has shell metacharacters, then you will have to quote at least those metacharacters. A metacharacter is:

    A character that, when unquoted, separates words. A metacharacter is a space, tab, newline, or one of the following characters: ‘|’, ‘&’, ‘;’, ‘(’, ‘)’, ‘<’, or ‘>’.

  2. If the value has !, and history expansion is enabled (which is usually the case in interactive shells), you will need to quote at least the ! using single quotes or a backslash. Double quotes aren't enough.

  3. If the value has a ~ and you want tilde expansion to happen, then "tilde-prefix" must be unquoted (so ~/ in "/some/path":~/"bar", or ~user/ in ~user/".config/app", etc.). This makes it possible to mix tilde expansion with paths containing spaces and such (so ~user/"some path (with metacharacters)").

  4. If the value has parameter expansions ($foo, ${foo}, etc.), or command substitutions ($(bar), or `foo`), or arithmetic expansions ($((a+b))), or something resembling those, then:

    1. Quote them with single quotes if you don't want the expansions to be performed. You can also use backslash, but then it's not sufficient to escape just $ in $(, as ( is a metacharacter as mentioned above and needs to be quoted as well.
    2. Not quoting them is fine if you want them expanded, or you can use double quotes.
  5. If the value has process substitutions (>(...) or <(...)) in it, that will only be performed if the substitution is unquoted.


Arrays are a different game from regular assignment. In general, the part inside (...) for a=(...) is expanded just like it would be anywhere else in the command line, so field splitting and filename expansion are performed. That makes it possible to do something like:

set -f
IFS=:
path=($PATH)

And get entries in $PATH as individual items in the array path.

5
  • I think you mean "… tokens also undergo field splitting …" as in between multiple individual tokens and not within each single token, am I reading correctly?
    – Raffa
    Nov 20 at 9:48
  • 1
    @Raffa as in after it undergoes the other stages (e.g., token undergoes command substitution, then the result of that undergoes field splitting). That doesn't happen with variable assignment.
    – muru
    Nov 20 at 10:15
  • 1
    Maybe because I didn't read the whole answer, but it is hard to spot where exactly it answers the question. Nov 20 at 23:32
  • @akostadinov see the rules of thumb. Whether you quote or not or which quotes you use depend on what the value looks like.
    – muru
    Nov 21 at 0:59
  • @muru, actually I like rules of thumb. I'm often irritated when I need something simple but it is buried somewhere inside a very long answer. And I realized that I myself often digressed in my answers. So I started to try putting simple instructions in the beginning as a tl.dr. and then go on with random thoughts and other things I find useful. Just saying, I see now that you gave a quality answer with best of intentions. So some lazy people complaining is probably not as big of a concern. Nov 22 at 9:54
6

There is no "standard" according to the Bash Reference Manual.

Variables (Shell parameters):

A variable may be assigned to by a statement of the form

name=[value]

Quoting:

Quoting is used to remove the special meaning of certain characters or words to the shell. Quoting can be used to disable special treatment for special characters, to prevent reserved words from being recognized as such, and to prevent parameter expansion.

On server systems, the default filenames will usually be standard alphanumeric characters, not containing any special characters, and quoting should generally not be needed (although exceptions may apply).

However on desktop systems, it's more common that filenames contain spaces and other special characters, and then the path should be quoted - and this is generally considered the "safe route".

If quoting, use the quotes that match your needs: Single quotes will treat every single character literally, while double quotes will still treat $, `, \ and ! as special.

But the criteria for quoting are separate for the syntax of assigning variables, so it entirely depends on the context of the variable (in this case the filename).

0
5

No quotes example:

filePath=Documents Folder 2
echo "$filePath"

This will echo Documents.
Everything after the first space will be lost. You need the quotes in order to retain the spaces. Not using quotes will work for single words only but it's not considered a good practice in general. It's better to use quotes anyway.

Double quotes example:

filePath="$HOME/Documents"
echo "$filePath"

This will echo /home/username/Documents

Single quotes example:

filePath='$HOME/Documents'
echo "$filePath" 

This will echo $HOME/Documents

If you want the system to use the characters as they are, use single quotes.
If you want the system to process variables or other special uses, use double quotes.

1
  • 9
    The first example tries to run Folder (with argument 2) with filePath set to Documents in its environment, but does not set filePath in the current shell. If it echos Documents for you, you must have set that value earlier.
    – DonHolgo
    Nov 20 at 9:54
0

Both will work, although slightly differently. The biggest difference is that between single quotes, most shell expansions (wildcards, variables, command substitution, etc) do not take place, so if your filename contains a variable, such as:

$HOME/Documents/myfile.txt

if you put this in 'single quotes' then it will be seen as starting with a literal $ character followed by "HOME" by whatever command/program the filename is sent to. Using "double quotes" allows expansion of variable names (so the above will have $HOME replaced by your actual home directory) but not wildcards, ie * ? [ ] etc. Escaping spaces and other "separator" characters, or closing (single or double) quotes before using the wildcard(s) allows them to work as usual.

On the flip side, if you don't put filenames or variables supposed to contain filenames in quotes, then anything containing spaces or tabs will be split into several arguments, which is normally not what you want.

1
  • Also, you may have noticed that bash's tab-completion doesn't use quotes but escapes separator/special characters (adds a \ before them) by default - this allows you to resolve ambiguities, continue to type the filename etc. without having to close the quote marks yourself.
    – dolt
    Nov 21 at 19:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .