bashshelldotfiles

Should I use quotes in environment path names?


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?


Solution

  • 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, and zsh, but NOT to (mostly) strictly POSIX compliant shells such as dash; thus, when you target /bin/sh, you MUST double-quote the RHS of export.[1]

    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:

    Example

    This example demonstrates that in bash, ksh, and zsh you can get away without double-quoting, even when using export, but I do not recommend it.

    #!/usr/bin/env bash
    # or ksh or zsh - but NOT /bin/sh!
    
    # Create env. variable with whitespace and other shell metacharacters
    export FOO="b:c &|<> d"
    
    # Extend the value - the double quotes here are optional, but ONLY 
    # because the literal part, 'a:`, contains no whitespace or other shell metacharacters.
    # To be safe, DO double-quote the RHS.
    export FOO=a:$foo # OK - $FOO now contains 'a:b:c &|<> d'
    

    [1] As @gniourf_gniourf points out: Use of export to modify the value of PATH 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.