You need to split that command substitution.
for user in $(<$1)
With $(...)
unquoted, splits on characters of $IFS
: space, tab, newline and nul by default¹. Here using the $(<file)
Korn-like operator rather than $(cat -- $1)
as an optimisation.
To split on newline (aka linef
eed) only, either do the same but after IFS=$'\n'
or use the f
parameter expansion flag (short for ps[\n]
):
for user in ${(f)"$(<$1)"}
Note the quotes to prevent IFS-splitting, and then the f
flag to split on newline.
You could also use a while read
loop:
while IFS= read -ru3 user; do
...
done 3< $1
One difference from the previous approaches is that it won't skip empty lines.
It will also skip characters after the last newline if any but those are not allowed in text files.
It avoids storing the whole file in memory but on the other hand means the file is going to be read one byte at a time as each read
needs to make sure it does not read past the newline character that delimits the line.
With:
for user in "${(f@)$(<$1)}"
Or:
IFS=$'\n\n'
for user in $(<$1)
Empty lines are preserved except for trailing ones as command substitution strips all trailing newline characters.
To read all lines into an array, also considering empty lines and the non-line made of the bytes after the last newline if any and loop over it, that becomes quite awkward, you could use a helper function:
lines() {
local ret
reply=( "${(@f)$(cat -- "$@"; ret=$?; echo .; exit $ret)}" )
ret=$?
reply[-1]=( ${reply[-1]%.} )
return $ret
}
lines myfile &&
for line in "$reply[@]"; do
something with "$line"
done
Also note that echo
should be avoided to output arbitrary data (though in the case of zsh
, you can actually use echo -E - $data
), better to use printf '%s\n' "$data"
as in any other shell or print -r -- "$data"
as in the Korn shell.
¹ note that contrary to other POSIX-like shells such as bash, zsh by default doesn't have that misfeature whereby the result is further subject to globbing, so you don't need set -o noglob
there as you would in sh
/bash
/ksh
for instance.
awk '{print "myWebSite.org/@/"$1}' userList.txt
– Edgar Magallon Mar 10 '23 at 02:31for
loop then remove the quotes from"$(cat $1)"
:for user in $(cat "$1");
but as I said it's not recommendable to use a loop – Edgar Magallon Mar 10 '23 at 02:36for
iterates over words rather than lines; see "Why you don't read lines withfor
" (it's in the BashFAQ/BashPitfalls, but applies reasonably well to zsh as well). Usewhile IFS= read -r user; do ... done <$1
instead. – Gordon Davisson Mar 10 '23 at 06:23