在 shell 脚本上使用变量循环 for

在 shell 脚本上使用变量循环 for

我有以下脚本,可以使用密钥通过 SSH 连接到服务器,并在那里生成很多内容。

#!/usr/bin/env bash

ssh -i mykey.pem myuser@SERVER_IP << 'ENDSSH'
[A LOT OF STUFF]
ENDSSH

(我用它来运行它sh scriptname.sh

现在我想在另一台服务器上进行相同的操作,因此我必须使用两个不同的文件(ip_1ip_2)通过SSH 连接到两个不同的服务器(和)。.pemmykey1.pemmykey2.pem

到目前为止,我知道如何循环 ip,如下所示:

#!/usr/bin/env bash

ip_list="ip_1 ip_2"

for ip in $ip_list; do
ssh -i mykey.pem myuser@$ip << 'ENDSSH'
[A LOT OF STUFF]
ENDSSH
done

但现在我还想循环以获得正确的 pem 文件。我怎样才能实现这个目标?也许还有另一个清单?有人可以为我提供一个优雅的解决方案吗?

  • ip_1应该使用mykey1.pem
  • ip_2应该使用mykey2.pem

提前致谢

答案1

由于您使用的是 bash,因此可以使用关联数组:

#!/usr/bin/env bash

declare -A ip_list=(["ip_1"]="mykey1.pem" ["ip_2"]="mykey2.pem")

for ip in "${!ip_list[@]}"; do
  ssh -i  "${ip_list[$ip]}" myuser@"$ip" << 'ENDSSH'
[A LOT OF STUFF]
ENDSSH
done

请注意,与常规索引数组不同,关联数组不按特定顺序保存,因此不能保证ip_1会在 之前进行处理ip_2


如果你需要要使用简单的 POSIX 兼容 shell,请创建一个包含 ip 和密钥文件的文件,每行一个:

$ cat iplist.txt
ip1 mykey1.pem
ip2 mykey2.pem

然后,使用这个脚本:

#!/bin/sh

while read -r ip key; do
    ssh -i "$key" myuser@"$ip" << 'ENDSSH'
[A LOT OF STUFF]
ENDSSH
done 

并运行它:

sh /path/to/script <  /path/to/iplist.txt

但如果你走那条路斯蒂芬的方法更好。

答案2

一种方法是while IFS=, read -r在 csv 此处文档上使用循环。

#! /bin/sh -
while IFS=, read <&3 -r ip key; do
  ssh -i "$key" "$ip" << ENDSSH
  ...
ENDSSH
done 3<< ENDCSV
10.0.0.1,p1.pem
10.0.0.2,p2.pem
ENDCSV

那么你甚至不需要要求用户安装 bash。如果可移植性不是问题,您可以使用zsh支持循环多个变量的替代方案。

#! /usr/bin/env zsh
for ip key (
  10.0.0.1 p1.pem
  10.0.0.2 p2.pem
) ssh -i $key $ip << ENDSSH
  ...
ENDSSH

答案3

set您的原始脚本可以通过内置方式变得更加可移植,并且将 ip 和 key 作为一个字符串组合在一起,以冒号分隔。我们稍后可以使用前缀和后缀去除来提取相应的条目

#!/usr/bin/env bash

# Set positional parameters
# Example ip addresses
set -- 192.168.0.1:mykey1 192.168.1.1:mykey2

# iterating without specifying 'in' assumes positiona parameters
for host; do
    ssh -i ${host##*:}.pem myuser@${host%%:*} << 'ENDSSH'
[A LOT OF STUFF]
ENDSSH

done

相关内容