Bash vs. Zsh - read (line)

I wasn’t sure where I can put it, but I am confused why I am getting different results trying to do (seemingly) same thing in bash and zsh shell. Here are a lot of experienced users and maybe somebody can clarify it a bit or give a helpful hint of what’s wrong. Basically if I run something of the sort in bash and zsh shells:

x=0 && echo -e "First\nSecond\nThird" | while read line; do echo $line && ((++x)); done; echo $x

In bash the output is always the original value of the variable x (0 in this case). While in zsh it seems to be incremented correctly and I am getting 3 (like I’d expect).
It would seem as if (in bash) the variable x was shadowed by another copy inside the while block which was destroyed at the end of the block, so the value of the original outer variable was read. But checking with something like:

x=1; while [ $x -lt 3 ]; do ((++x)); done; echo $x

I see that it’s not the case, as I am getting the correct output (3) in both shells.

So, the case must be in the read utility then? I guess bash respects the read’s POSIX compliant definition and basically it does what the manpages say and zsh uses some builtin version of read? Or I am totally overthinking it and it’s something dead simple (I am new to shells and using zsh pretty much exclusively).

Other shells

ksh’s output is identical to that of zsh, while sh’s is equal to bash’s. Couldn’t get it working in fish, because fish is weird :slight_smile:

Are you wanting something like this?

 x=0 && echo -e "First\nSecond\nThird" | (while read line; do echo $line ; ((++x)); done; echo $x)

Yep, that’s it, thanks :slight_smile: So, it was indeed a different variable that was incremented the way I was doing it.

edit: the solution is working, but does a bit different thing that is done in zsh. After the subshell is exited I can’t reference the (incremented) x (echo it for example), while in zsh the declared at the beginning x gets modified and can be referenced afterwards.

1 Like

Just to complement, zsh and bash are different shells, though most of their functions and sintaxe are the same there are differences.

For example arrays can be set in the same way for both, but is different for ksh.

I use zsh on my terminals here but I always write scripts as #!/bin/bash cause there is more documentation on the net, so is better to track for something wrong in the code.

1 Like

It’s possible to use ksh-like arrays in zsh as well :slight_smile:

Zsh seems to be more flexible shell in general…

edit: okay, it seems that read is indeed a builtin in zsh (and ksh), so it doesn’t fork off the main process, while it’s not the case in bash.

trap "((++forks))" CHLD; x=0 && echo -e "First\nSecond\nThird" | while read line; do ((++x)); done; echo "x=$x; forks=$forks"

gives me as output
in zsh: x=3; forks=1
in bash: x=0; forks=3

Suspected that and it was probably obvious, but I learned something :slight_smile:

1 Like