What does this zsh for syntax mean?

4

I working on source controlling my dotfiles and a lof of what I'm doing is based off of Zach Holman's dotfiles. I want to source all zsh files like he does in his files but before I just throw the code in there I want to actually understand what the code is doing. The snippet I'm confused with is

# all of our zsh files
typeset -U config_files
config_files=($ZSH/**/*.zsh)

# load the path files
for file in ${(M)config_files:#*/path.zsh}
do
  source $file
done

# load everything but the path and completion files
for file in ${${config_files:#*/path.zsh}:#*/completion.zsh}
do
  source $file
done

# initialize autocomplete here, otherwise functions won't be loaded
autoload -U compinit
compinit

# load every completion after autocomplete loads
for file in ${(M)config_files:#*/completion.zsh}
do
  source $file
done

unset config_files

Mostly I'm confused as to what is happening here

${(M)config_files:#*/path.zsh}

and here

${${config_files:#*/path.zsh}:#*/completion.zsh}

So what does this all mean?

Rumel

Posted 2014-09-02T17:42:59.123

Reputation: 217

Answers

4

The PARAMETER EXPANSION section of the zshexpn man page is a good starting point.

First, lets note that $config_files is an array including all .zsh files under the $ZSH directory, as you can see in the second line: config_files=($ZSH/**/*.zsh).

This syntax used in the line ${(M)config_files:#*/path.zsh} (please note, that M inside the parentheses is called an expansion flag) is the following:

${name:#pattern}
          If  the  pattern matches the value of name, then substitute the  
          empty string; otherwise, just substitute the value of name.  
          If name  is an array the matching array elements are removed 
          (use the `(M)' flag to remove the non-matched elements).

In other words, the for loop in question iterates over all path.zsh files in $ZSH. You could use for file in $ZSH/**/path.zsh as well, but the operation on the $config_files file array is faster than recursively searching the file system again and again. (There are more for loop, aren't there?)

With that knowledge it should be easy to figure out what ${${config_files:#*/path.zsh}:#*/completion.zsh} will do. (The result is stated in the comment anyhow).


I usually use some trivial examples to get a better understanding myself:

$ array=(foo bar baz)
$ print ${array}
foo bar baz
$ print ${array:#ba*}
foo
$ print ${(M)array:#ba*}
bar baz

It's easier than it looks like, right?! ;)

mpy

Posted 2014-09-02T17:42:59.123

Reputation: 20 866