shell zsh add tag
PeterVandivier
When testing parts of long shell scripts, sometimes I like to copy-paste parts of the script to another shell session and execute them line-by-line.

I recently changed my default shell to `zsh` [at the naggy insistence of my MacBook Pro][1]. Since I did this though, I can't seem to debug for-loops. This sucks. 

Given a file at `/tmp/foo.csv` of the form...

```csv
a,b
1,x
3,z
2,y
```

...and a `/tmp/foo.sh` of the form...

```sh
order=`tail -n +2 foo.csv | sort --field-separator=',' --key=1 -n`
for row in $order
do
  file=`echo $row | awk -F"," '{print $2}'`
  eval "./$file.sh"
done
```

...(and also)...

```sh
cd /tmp

echo 'echo x' > x.sh
echo 'echo y' > y.sh
echo 'echo z' > z.sh

chmod +x *.sh
```

...when I copy-paste the for-loop into a shell session, I get this error!

```sh
➜  /tmp for row in $order
do
  file=`echo $row | awk -F"," '{print $2}'`
  eval "./$file.sh"
done
zsh: no such file or directory: ./x
zsh: command not found: y
zsh: command not found: z.sh
➜  /tmp
```

What _really sucks_ though is that this behaviour is not repeatable when you execute the file _even without a shebang_.

```sh
➜  /tmp echo $SHELL
/bin/zsh
➜  /tmp ./foo.sh
x
y
z
➜  /tmp
```

You _can_ get similar bad behaviour in the file invocation if you explicitly specify `zsh` in the ./foo.sh shebang. 

```sh
➜  /tmp cat foo.sh
#!/usr/bin/env zsh
order=`tail -n +2 foo.csv | sort --field-separator=',' --key=1 -n`
for row in $order
do
  file=`echo $row | awk -F"," '{print $2}'`
  eval "./$file.sh"
done
➜  /tmp ./foo.sh
(eval):1: no such file or directory: ./x
(eval):2: command not found: y
(eval):3: command not found: z.sh
➜  /tmp

```

So it _appears_ that either `zsh` or some "helpful" setting in [ohmyzsh][2] is using `bash` for file invocation when no shebang is specified except...

```sh
➜  /tmp echo $SHELL
/bin/zsh
➜  /tmp echo 'echo $SHELL' > bar.sh
➜  /tmp chmod +x bar.sh
➜  /tmp ./bar.sh
/bin/zsh
➜  
```

So... wtf `zsh`, what gives?

[1]: https://www.theverge.com/2019/6/4/18651872/apple-macos-catalina-zsh-bash-shell-replacement-features
[2]: https://ohmyz.sh/
Top Answer
Skillmon
There's just one tiny bit of change necessary. In Zsh if you want to loop over rows in a variable, the variable must be an array. Arrays are initialized with `()` around them (see [the documentation](http://zsh.sourceforge.net/Doc/Release/Parameters.html#Array-Parameters)).

If you declare `order` like this:

```zsh
order=($(tail -n +2 foo.csv | sort --field-separator=',' --key=1 -n))
```

everything should work (note that I changed the backticks to `$(` and `)` as that's the preferred syntax in Zsh over the easy to miss ticks).

So your `foo.sh` should look like this (replace the shebang with the correct one on your system):

```zsh
#!/usr/bin/zsh

order=($(tail -n +2 foo.csv | sort --field-separator=',' --key=1 -n))
for row in $order
do
    file=$(echo $row | awk -F"," '{print $2}')
    eval "./$file.sh"
done
```

The other files can stay the same.

Enter question or answer id or url (and optionally further answer ids/urls from the same question) from

Separate each id/url with a space. No need to list your own answers; they will be imported automatically.