I'm in the process of cleaning up all my config files in an attempt to make them as readable as possible. I've been looking for a style guide on the use of quotes while exporting paths in, for example, a ~/.bashrc
file:
export PATH="/users/me/path:$PATH"
vs
export PATH=/users/me/path:$PATH
The Google shell style guide suggests avoiding quotes for path names. In contrast, a lot of the popular dotfiles repos (such as Zach Holman's here) use quotes. Are there any situations when it is an advantage to use quotes in the path?
I used these answers above when setting environment path names in a docker .env file, and got bit. I'm putting this here for anyone else looking for how to define environment variables for docker.
Docker compose reads environment variables from an .env file that exists in the same folder that docker compose is run as stated here https://docs.docker.com/compose/env-file.
However instead of wrapping the value in quotes, docker compose needs the environment variable defined without quotes, unless the quotes are part of the value. Again, as stated in the url above
I was trying to set
NODE_PATH=./src
for absolute paths to work in a react app being deployed by docker, but had written it asNODE_PATH="./src"
. This warning pulled me out of 4 hour rabbit hole.test 123
is a valid path name on UNIX. TryIt will return:
Or even
which will return
Does it answer your question?
Honestly I would not follow such fourth party style guides. Although I'm astonished that even Google advertises such wrong advices.
I would follow:
(to be carefully extended)
Tip of the hat to @gniourf_gniourf and @chepner for their help.
tl;dr
To be safe, double-quote: it'll work in all cases, across all POSIX-like shells.
If you want to add a
~
-based path, selectively leave the~/
unquoted to ensure that~
is expanded; e.g.:export PATH=~/"bin:$PATH"
. See below for the rules of~
expansion in variable assignments.Alternatively, simply use
$HOME
inside a single, double-quoted string:export PATH="$HOME/bin:$PATH"
NOTE: The following applies to
bash
,ksh
, andzsh
, but NOT to (mostly) strictly POSIX compliant shells such asdash
; thus, when you target/bin/sh
, you MUST double-quote the RHS ofexport
.[1]sh
, whenexport
is used, so always double-quote there.The reason you can get away without double-quoting in this case is that variable-assignment statements in POSIX-like shells interpret their RHS differently than arguments passed to commands, as described in section 2.9.1 of the POSIX spec:
Specifically, even though initial word-splitting is performed, it is only applied to the unexpanded (raw) RHS (that's why you do need quoting with whitespace/metacharacters in literals), and not to its results.
This only applies to genuine assignment statements of the form
<name>=<value>
in all POSIX-like shells, i.e., if there is no command name before the variable name; note that that includes assignments prepended to a command to define ad-hoc environment variables for it, e.g.,foo=$bar cmd ...
.Assignments in the context of other commands should always be double-quoted, to be safe:
With
sh
(in a (mostly) strictly POSIX-compliant shell such asdash
) an assignment withexport
is treated as a regular command, and thefoo=$bar
part is treated as the 1st argument to theexport
builtin and therefore treated as usual (subject to word-splitting of the result, too).(POSIX doesn't specify any other commands involving (explicit) variable-assignment;
declare
,typeset
, andlocal
are nonstandard extensions).bash
,ksh
,zsh
, in an understandable deviation from POSIX, extend the assignment logic toexport foo=$bar
andtypeset/declare/local foo=$bar
as well. In other words: inbash
,ksh
,zsh
,export/typeset/declare/local
commands are treated like assignments, so that quoting isn't strictly necessary.dash
, which also chose to implement the non-POSIXlocal
builtin[2] , does NOT extend assignment logic to it; it is consistent with itsexport
behavior, however.Assignments passed to
env
(e.g.,env foo=$bar cmd ...
) are also subject to expansion as a command argument and therefore need double-quoting - except inzsh
.env
acts differently fromexport
inksh
andbash
in that regard is due to the fact thatenv
is an external utility, whereasexport
is a shell builtin.(
zsh
's behavior fundamentally differs from that of the other shells when it comes to unquoted variable references).Tilde (
~
) expansion happens as follows in genuine assignment statements:~
needing to be unquoted, as usual, it is also only applied:~
; e.g.:foo=~ # same as: foo="$HOME"
~
starts the string or is preceded by an unquoted:
~
is followed by an unquoted/
.foo=~/bin # same as foo="$HOME/bin"
foo=$foo:~/bin # same as foo="$foo:$HOME/bin"
Example
This example demonstrates that in
bash
,ksh
, andzsh
you can get away without double-quoting, even when usingexport
, but I do not recommend it.[1] As @gniourf_gniourf points out: Use of
export
to modify the value ofPATH
is optional, because once a variable is marked as exported, you can use a regular assignment (PATH=...
) to change its value.That said, you may still choose to use
export
, so as to make it explicit that the variable being modified is exported.[2] @gniourf_gniourf states that a future version of the POSIX standard may introduce the
local
builtin.