Зацикливание for с переменными в сценарии оболочки

Согласно википедии System V предшествовала System III, выпуск UNIX / TS 3. Поскольку официального выпуска UNIX / TS 4 не было, System III была заменена непосредственно System V.

3
26.03.2019, 13:28
3 ответа

Один из способов сделать это — использовать цикл 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
6
27.01.2020, 21:08

Поскольку вы используете 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 оболочку, создайте файл с файлами 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

Но если вы пойдете по этому пути, подход Стефана лучше.

6
27.01.2020, 21:08

Ваш исходный скрипт можно сделать немного более переносимым с помощью setвстроенного -, а также объединить ip и ключ в одну строку, разделенную двоеточием. Позже мы можем использовать удаление префикса и суффикса для извлечения соответствующей записи

#!/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
1
27.01.2020, 21:08

Теги

Похожие вопросы