In FreeBSD 12, using the zsh shell, I noticed this difference when looking at $path (lowercase) versus $PATH (uppercase).

echo $path

/sbin /bin /usr/sbin /usr/bin /usr/local/sbin /usr/local/bin /usr/home/freebsd/bin

echo $PATH


One output is delimited by SPACE character, the other by COLON character.

➥ Why the difference?

Are these two different, separate variables? Or does the lowercase/uppercase trigger some kind of trick or meaning I do not know about?

Is this a zsh feature? Or a feature of FreeBSD?

  • 1
    Aside: In any POSIX-compliant shell, variable names with any lowercase characters are guaranteed safe for application use (not to silently modify shell or system behavior when changed). This is one of the places where zsh's decision to only follow the standard where it makes sense to them can make headaches for script authors, because the standardized guarantees don't apply. – Charles Duffy Jul 26 at 11:22
  • @CharlesDuffy do you have a link to the part of the standard where it says any of that about the lower and upper case variables? Thanks. – mosvy Jul 28 at 9:41
  • @mosvy, pubs.opengroup.org/onlinepubs/9699919799/basedefs/… -- read it keeping in mind that shell and environment variables share a single namespace (setting the a shell variable updates the value of any existing like-named environment variable; setting an environment variable initializes shell variables). The specific lines: The name space of environment variable names containing lowercase letters is reserved for applications. Applications can define any environment variables with names from this name space without modifying the behavior of the standard utilities. – Charles Duffy Jul 28 at 14:15
  • @CharlesDuffy That doesn't apply here. Setting path inside zsh will not update any path envvar: path=junk zsh -c 'echo $path; path=garbage; /usr/bin/printenv path'. – mosvy Jul 28 at 14:23
  • @mosvy, you've convinced me that it doesn't violate the letter of the standard. The spirit, on the other hand, would make for path in "$dir"/* reflexively safe-to-write code. – Charles Duffy Jul 28 at 14:25

That's a feature of zsh inherited from csh/tcsh.

The $path array variable is tied to the $PATH scalar (string) variable. Any modification on one is reflected in the other.

In zsh (contrary to (t)csh), you can tie other variables beside $PATH with typeset -T. It's conventional, but not mandatory, to use an uppercase name for the colon-separated scalar and the same name in lowercase for the array. While colon is the default separator, other separators can be used (for instance newline to tie a multi-line string to an array, or comma to tie a csv row to an array)

In recent versions of zsh, typeset -p PATH or typeset -p path shows the link between the two variables:

% typeset -p path
typeset -aT PATH path=( /home/chazelas/bin /usr/local/bin /usr/bin /bin )

That's useful in that it makes it easier to add remove components or loop over them.

Doing a typeset -U path to make the elements unique also helps keeping the $PATH variable clean (something similar can be achieved in tcsh with set -f).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.