read in Bash and ZSH

I'm observing differences between zsh and bash when using read on macOS.

With bash this script

echo "characters" | while IFS= read -d '' -n 1 a; do printf %s "$a-"; done

Produces

c-h-a-r-a-c-t-e-r-s-

Whereas on zsh I have no output and no errors Is it possible to use read to iterate character by character?


Solution 1:

The options for the read command are significantly different between bash and zsh. In this case, the problem is that -n has completely different meanings between the two: in bash, it says how many characters to read, while in zsh it modifies the -p or -l options (which have to do with completion functions, and are irrelevant here).

In zsh, you use -k to specify the number of characters to read, but it also defaults to reading from the terminal rather than stdin, so you have to also add -u 0 to tell it to read from stdin.

Long story short: in zsh, use read -n '' -k 1 -u 0 somevar to read a single character from stdin.

BTW, there are lots more differences between read in bash vs zsh (and vs other shells). The POSIX standard only specifies the -r option; everything else is a nonstandard addition, and any similarity between different shells' extensions should be considered a happy accident.