I’ve been studying zsh scripting for all of 2 hours at this point and I’ve hit a wall. I want to go through a list of files that may have spaces in them. I’m open to completely different approaches than the following example so long as they’re zsh since zsh is what I’m studying, not the task I’m trying to script.
files=(`ls`)
for f in $files; do
print $f
done
I’m obviously not just recreating ls, I just want $f to capture the entire file name each iteration of the loop.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
First, I assume that the use of ls is just an example. You cannot parse the output of ls in any shell, because it is ambiguous. Read Why you shouldn’t parse the output of ls(1) if this is news to you. In any shell, to obtain a list of files, use wildcards, e.g. files=(*).
In zsh, like in other shells, the result of command substitution is split into words at whitespace characters (more precisely, according to the value of IFS). (Unlike other shells, the result of command substitution is not subject to globbing in zsh.) So if the output of the ls command is
hello world wibble
then files=($(ls)) sets the files array to contain 3 elements: hello, world and wibble.
If the command substitution is in double quotes, then no splitting is performed. You can perform custom splitting with parameter expansion flags. Use the @ flag to indicate that the result of the splitting is to be an array (oddly, you need to keep the expansion in double quotes, i.e. "${(@)…}", even though the double-quoted string will expand to multiple words). For splitting, use the s flag, e.g. "${(@s:,:)…}" to split at commas; the f flag splits at newlines only.
files=("${(@f)$(ls)}")
Note that the proper way to iterate over an array in general is for f in $files[@], as $files strips off empty elements (here, it doesn’t matter because the elements won’t be empty).
print $f interprets $f as a switch if it begins with a - and expands backslashes in $f. Use print -r -- $f, or print -rn -- $f if you don’t want to add a newline after the string.
Method 2
In zsh you can use the shell’s expansion which does not perform word splitting by default. Try
for f in /path/to/files/*; do
print ${f}
done
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0