1
$ zsh --version
zsh 5.8 (x86_64-apple-darwin19.6.0)
$ tmux -V
tmux 3.2a

I am automating a remote server monitoring dashboard in tmux via zsh script.

  1. Store the multiline output of a command as an array in zsh: (WORKS)
$ server_name_array=( $( aws ec2 describe-instances... ) )
$ declare -p server_name_array
typeset -a server_name_array=( name1 name2 name3 )
  1. Then want to use both the index and value of each array item in my tmux command: (DOES NOT WORK)
$ for i in "${!server_name_array[@]}"; \
do \
  tmux send-keys -t '=server:=servers.<server_name_index>' 'ssh <server_name_value> -t "<my-remote-command>"'; \
done;

But I get the following error:

zsh: event not found: server_name_array[@]

I have read this is due to the special ! operator in bash and have tried escaping / unsetting it as suggested to no avail:

$ set +H
$ for index in "${"'!'"server_name_array[@]}"; do echo $index; done;
zsh: bad substitution
$ for index in "${"\!"server_name_array[@]}"; do echo $index; done;
zsh: bad substitution
$ for index in "${"'!'"server_name_array[@]}"; do echo $index; done;
zsh: bad substitution
$ for index in "${"\!"server_name_array[@]}"; do echo $index; done;
zsh: bad substitution
$ for index in "${!server_name_array[@]}"; do echo $index; done;
zsh: event not found: server_name_array[@]
$ for index in "${\!server_name_array[@]}"; do echo $index; done;
zsh: bad substitution

What am I doing wrong?

UPDATE:

Here is my script invoked via .sh file:

$ ls -ahl /usr/local/bin/server_mon
lrwxr-xr-x  1 <user>  admin    48B <date> /usr/local/bin/server_mon -> ~/scripts/server_mon.sh
#!/bin/sh

set -euC

cd <project-directory>

# our main function
attach() {
    [ -n "${TMUX:-}" ] &&
        tmux switch-client -t '=server' ||
        tmux attach-session -t '=server'
}

# attach to server if it already exists
if tmux has-session -t '=server' 2> /dev/null; then
    attach
    exit 0
fi

# start a named session called server
tmux new-session -d -s 'server' -n 'local'; \

# new tmux servers window
tmux new-window -d -t '=server' -n 'servers'; \

# store the names of our server instances in an array
server_name_array=( $( aws ec2 describe-instances ... ) )
declare -p server_name_array
# typeset -a server_name_array=( name1 name2 name3 )
server_name_array_length=${#server_name_array[@]:1}

# create split panes for number of servers (n-1)
for i in "${server_name_array[@]:1}"; do tmux split-window -t '=server:=servers' -d; done;
# select an even vertical layout
tmux select-layout -t '=server:=servers' even-vertical;

# vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
# HERE IS WHAT I AM TRYING TO DO
# vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv

# Loop over ZSH array of server names, and send ssh commands containing server names to panes via the array index
for i in "${!server_name_array[@]}"; 
do
    # tmux send-keys -t '=server:=servers.<server_name_index>' 'ssh <server_name_value> -t "<my-remote-command>"';
    tmux send-keys -t '=server:=servers.${$i}' 'ssh ${server_name_array[$i] -t "sudo su;"' Enter; 
done;
4
  • 3
    "What am I doing wrong?" -- in my opinion, trying to write a program that both bash and zsh can run. Pick one or the other. Commented Apr 19, 2022 at 19:28
  • @glennjackman My script has #!/bin/sh at the top. I'm using zshell in terminal. Testing these command I am using the terminal. When I run the script aliased to <script.sh>, is ZSH running it or BASH? Commented Apr 19, 2022 at 19:56
  • clearly zsh is, as you get the zsh error. Show the content of the script and especially show exactly how you invoke it. Commented Apr 19, 2022 at 19:58
  • 6
    @eschie If you're using a generic #!/bin/sh shebang, you shouldn't use any non-POSIX features (like arrays) at all, because you aren't in control of which shell the scripts runs under. Do not worry about figuring out what /bin/sh is on your system, because that's subject to change. If you want to use non-POSIX features, you should pick a specific shell, use a shebang that specifies that shell, and then use that shell's syntax. Commented Apr 19, 2022 at 20:17

1 Answer 1

4

Following script produces same result in bash and zsh :

declare -a server_name_array=(a b c)

test "$ZSH_VERSION" && c=1 || c=0

for ((i=0; i<${#server_name_array[@]}; i++)); do
    echo $i "${server_name_array[i+c]}"
done

output :

$ bash test.sh
0 a
1 b
2 c
$ zsh  test.sh
0 a
1 b
2 c
Sign up to request clarification or add additional context in comments.

3 Comments

I'm on zsh 5.8.1 (x86_64-apple-darwin21.0) and I don't get the same result.
@MehrshadKhansarian I get same result on zsh 5.9 (x86_64-apple-darwin22.1.0). Can you post your result ?
I am sorry, I was mistaken. I hadn't noticed the i+c index, which practically starts indexing at 1 on zsh and 0 on bash.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.