Reputation: 157
I just want to pass a glob through and then use it against ls directly. The simplest example would be:
test() { ls -d ~/$1 }
alias test="noglob test"
test D*
If I simply run ls D
in my home directory: it outputs three files. but if I run the snippet provided, I get "/Users/jubi/D*": No such file or directory
. What should I be doing? thanks!
Upvotes: 0
Views: 1501
Reputation: 7634
The authoritative and complete documentation of Zsh expansion mechanism is located at http://zsh.sourceforge.net/Doc/Release/Expansion.html.
Here's the reason your version doesn't work:
If a word contains an unquoted instance of one of the characters ‘*’, ‘(’, ‘|’, ‘<’, ‘[’, or ‘?’, it is regarded as a pattern for filename generation, unless the GLOB option is unset.
emphasis mine. Your glob operator, generated by parameter expansion, isn't considered unquoted.
You need the GLOB_SUBST
option to evaluate the parameter expansion result as a glob pattern. a setopt globsubst
, unsetopt globsubst
pair works, of course, but the easiest way is to use the following pattern specifically for this purpose:
${~spec}
Turn on the GLOB_SUBST option for the evaluation of spec; if the ‘~’ is doubled, turn it off. When this option is set, the string resulting from the expansion will be interpreted as a pattern anywhere that is possible, such as in filename expansion and filename generation and pattern-matching contexts like the right hand side of the ‘=’ and ‘!=’ operators in conditions.
In nested substitutions, note that the effect of the ~ applies to the result of the current level of substitution. A surrounding pattern operation on the result may cancel it. Hence, for example, if the parameter foo is set to
*
,${~foo//\*/*.c}
is substituted by the pattern*.c
, which may be expanded by filename generation, but${${~foo}//\*/*.c}
substitutes to the string*.c
, which will not be further expanded.
So:
t () { ls -d ~/${~1} }
alias t="noglob t"
By the way, test
is a POSIX shell builtin (aka [
). Don't shadow it.
Upvotes: 4