8

I'm trying to figure out how to do a command to multiple items. For example:

mycommmand fileA; mycommand fileB; mycommand fileC;

I can do it like this:

files=(fileA fileB fileC)
for fl in $files; mycommand $fl

When I try to inline this it fails:

$for fl in (fileA fileB fileC); echo $fl
zsh: invalid mode specification

Is this possible in zsh? I scanned through the manual on arrays but it didn't mention how to do this.

1
  • Just get rid of the in word. Mar 29 '20 at 18:57
12
$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 of man 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 as for 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

3
  • Thanks for the explanation, I just knew how I always did it :) Never took the time to research in in such depth, and mostly use bash anyway.
    – SadBunny
    Feb 12 '15 at 22:52
  • how to do it without files? Mar 29 '20 at 18:55
  • @theonlygusti: The syntax is not specific to files. "fileA" etc. in the example is just a string.
    – mpy
    Mar 29 '20 at 19:43
2

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

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.