← Back to context

Comment by kragen

3 hours ago

Not quoting the tilde doesn't help:

    : tmp; echo $PATH:~
    /usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:~

Edit: mjmas points out that I am wrong, because different Calvinball rules apply to variable assignments:

    : tmp; x=$PATH:~
    : tmp; echo "$x"
    /usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/home/user

Also in general your advice is very bad advice. In command-line arguments, which is the vast majority of the code of any shell script, you should always quote strings that contain variable expansion unless you want them to be implicitly split on spaces after variable expansion, because the thing you're storing in the variable is not an atomic string but rather a space-separated list.

This is almost never what you actually want, and in the rare cases that you do want to store a list, the shell's implicit space splitting usually breaks on filenames containing spaces. Bash has actual array variables which make it possible, but horrible, to handle this in a first-class way:

    : tmp; x=("foo bar" baz)
    : tmp; echo "${x[@]}"
    foo bar baz
    : tmp; touch "${x[@]}"
    : tmp; ls -l "${x[@]}"
    -rw-r--r-- 1 user user 0 Oct 11 17:52  baz
    -rw-r--r-- 1 user user 0 Oct 11 17:52 'foo bar'

This ksh feature is absent in the Bourne shell and in dash, but MirBSD ksh, Bash, and zsh all have it.

In general, whenever you see a $variable $expansion in a shell script outside of double quotes, you should suspect that the shell script will probably fail if your filenames or directory names contain spaces. In very many cases, this results in path injection security vulnerabilities. There are contexts where unquoted $variable $expansion is safe, but they are relatively rare.

However, relevant detail here! One of those safe contexts is actually variable assignment, where as mjmas pointed out in their helpful comment below, unquoted variable expansion is actually perfectly safe:

    : tmp; a='x  y'
    : tmp; b=α:$a:ω
    : tmp; echo "$b"
    α:x  y:ω

Bash does it only inside variable assignments:

  a=123:~
  echo $a
  echo 123:~

results in:

  123:/home/me
  123:~