What’s the zsh way to read n characters from stdin

readzsh

In bash, if I wanted to read, say 3, characters from a pipe, I could do:

... | read -n3

In zsh's read, the closest option seems to be -k:

-k [ num ]
Read only one (or num) characters. All are assigned to the first
name, without word splitting. This flag is ignored when -q is present. Input is read from the terminal unless one of -u or -p is
present. This option may also be used within zle widgets.

Note that despite the mnemonic ‘key’ this option does read full
characters, which may consist of multiple bytes if the option
MULTIBYTE is set.

And for -u and -p:

-u n
Input is read from file descriptor n.

-p
Input is read from the coprocess.

A bare echo foobar | (read -k3; echo $REPLY) hangs waiting for input. -p fails with
read: -p: no coprocess. Only the following works:

echo foobar | (read -k3 -u0; echo $REPLY)

This is the first time I'm seeing something that's more difficult to achieve in zsh than in bash.

Is there a simpler way to read N characters from stdin (whatever that might be) than this?

Best Answer

It's a bit weird, but it is documented:

-k [num]

(…) Input is read from the terminal unless one of -u or -p is present.

The reason your first attempt hangs there is that it's reading from the terminal. Typing three characters on the terminal does unblock it. To read from standard input when you're asking for a limited number of characters rather than a whole line (with -k or -q), you need to pass -u 0 explicitly.

echo foobar | ( read -u 0 -k 3; echo $REPLY )
Related Question