Home > Enterprise >  How can I loop over zsh array and use index and value in other commands?
How can I loop over zsh array and use index and value in other commands?

Time:04-20

$ 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;

CodePudding user response:

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
  • Related