Iterating over inline array in zsh
$for fl in (fileA fileB fileC); echo $fl
Here, (
is parsed as the beginning of a Glob Qualifier, like in ls *(a+2)
.
The qualifier f
stands for files with access rights matching spec, that's why you get the error invalid mode specification, because ileA
is not a valid access right spec.
If you try e.g. $for fl in (anotherfileA fileB fileC); echo $fl
you get zsh: number expected
, because the a
qualifier is to select by access time. And so on...
So, how to do it right? -- In zsh there are two possible syntaxes for for loops:#
-
Number one is described in the man page:
for name ... [ in word ... ] term do list done
So, as @SadBunny already pointed out, the correct syntax of your example is
for fl in fileA fileB fileC; echo $fl
-
Number 2 is for the lazy people like me (count the key strokes
;)
), documented in the ALTERNATE FORMS FOR COMPLEX COMMANDS section ofman zshmisc
:for name (word ...) { cmd1; cmd2; }
which can be simplified for only one command in the loop body by omitting the curly brakets:
for fl (fileA fileB fileC) echo $fl
This form has IMHO two main advantages:
- easyier to remember (exactly one pair of round brackets, no or one pair of curly brackets)
- works as
for fl (fileA fileB fileC) mycommand $fl
as well asfor fl ($files) mycommand $fl
-- same syntax for literal values or variables.
# Not counting the arithmetic for loops in the form for (( [expr1] ; [expr2] ; [expr3] )) do list done
Sure it's possible. Remove the brackets:
monsterkill-ub-dt% for fl in (xfile yfile); cat ${fl}
zsh: invalid mode specification
monsterkill-ub-dt% for fl in xfile yfile; cat ${fl}
x
y
This also works:
monsterkill-ub-dt% for fl in *; cat ${fl}
x
y