2013-12-01 3 views
1

Для моего текущего варианта использования я создаю скрипт scp, который скопирует файлы журналов с одного сервера на один или несколько других серверов.Итерации по нескольким ассоциативным массивам

I.e.

server1:/my/path1/log-files.* --> log_server1:/log/path1/server1 
server1:/my/path2/log-files.* --> log_server2:/log/path/server1 
server1:/my/path3/log-files.* --> log_server1:/log/path2/server1 

Я хотел бы иметь возможность использовать ассоциативные массивы (массивы) в Баш (версия 4) для конфигурации файла журнала, и цикл по всем А. Массивы, помещая их имена в индексированный массив.

Но я не понимаю, как я ссылаюсь на именованный массив A., используя переменную как имя A. Array.

Пример:

#!/bin/bash 
# GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu) from RedHat/CentOS 6.4 
declare -A log_server1 log_server2 
log_server1=([name]="ls1" [user]="user") 
log_server2=([name]="ls2" [user]="user") 

declare -A log1 log2 log3 
log1=([log_server]="log_server1" [path]="/my/path1" [file]="log-files" [rpath]="/log/path1/server1") 
log2=([log_server]="log_server2" [path]="/my/path2" [file]="log-files" [rpath]="/log/path/server1") 
log3=([log_server]="log_server1" [path]="/my/path3" [file]="log-files" [rpath]="/log/path2/server1") 

logs=(log1 log2 log3) 

for log in ${logs[@]} 
do 
    # How can I now refer to the A. Array by the name of "log1", etc ? 
    ... 
done 

ответ

2

Вы можете использовать indirect expansion, но это действительно некрасиво!

#!/bin/bash 

declare -A log_server1=([name]="ls1" [user]="user") 
declare -A log_server2=([name]="ls2" [user]="user") 

declare -A log1=([log_server]="log_server1" [path]="/my/path1" [file]="log-files" [rpath]="/log/path1/server1") 
declare -A log2=([log_server]="log_server2" [path]="/my/path2" [file]="log-files" [rpath]="/log/path/server1") 
declare -A log3=([log_server]="log_server1" [path]="/my/path3" [file]="log-files" [rpath]="/log/path2/server1") 

logs=(log1 log2 log3) 

for log in "${logs[@]}"; do 
    l_ls=$log[log_server] 
    l_p=$log[path] 
    l_f=$log[file] 
    l_rp=$log[rpath] 
    echo "array $log:" 
    echo " log_server => ${!l_ls}" 
    echo " path => ${!l_p}" 
    echo " file => ${!l_f}" 
    echo " rpath => ${!l_rp}" 
done 

В разделе руководства эталонным я связан выше, вы будете читать:

Если первый символ параметра восклицательным знаком (!), уровень переменной косвенностью вводится. Bash использует значение переменной, сформированной из остальной части параметра, как имя переменной; эта переменная затем расширяется и это значение используется в остальной части подстановки, а не значение самого параметра. Это называется косвенным расширением. Исключением являются разложения ${!prefix} и ${!name[@]}, описанные ниже. Восклицательный знак должен немедленно следовать за левой скобкой, чтобы ввести косвенность.

Вопрос. Почему не вы, вместо этого, создавать ассоциативные массивы log_server, path, file и rpath с ключами log1, log2 и log3? как в:

#!/bin/bash 

declare -A log_server1=([name]="ls1" [user]="user") 
declare -A log_server2=([name]="ls2" [user]="user") 

declare -A log_server path file rpath 

log_server[log1]="log_server1" 
path[log1]="/my/path1" 
file[log1]="log-files" 
rpath[log1]="/log/path1/server1" 

log_server[log2]="log_server2" 
path[log2]="/my/path2" 
file[log2]="log-files" 
rpath[log2]="/log/path/server1" 

log_server[log3]="log_server3" 
path[log3]="/my/path3" 
file[log3]="log-files" 
rpath[log3]="/log/path2/server1" 

for log in "${!log_server[@]}"; do 
    echo "log server $log:" 
    echo " log_server => ${log_server[$log]}" 
    echo " path => ${path[$log]}" 
    echo " file => ${file[$log]}" 
    echo " rpath => ${rpath[$log]}" 
done 
+0

Hell-вот ... Я посмотрел вокруг этого некоторое время, но это не гуманного приходят легко - таким образом, ваш вывод - уродливый - действителен. Это не будет хорошо читаемо для других, я скажу ... – sastorsl

+0

Интересно ваше предложение по другому способу работы над этой конкретной проблемой. Несмотря на то, что ваш первоначальный ответ отвечает на мой вопрос более общим образом в отношении ассоциативных массивов и циклизации более чем одного массива. Как вы видели, я также использую ассоциативный массив для определения хоста сервера журналов, к которому также нужно обратиться. Я почти завершаю: не инструмент для работы, но это интересное предприятие в bash не то же самое. – sastorsl

+0

Я вижу, где я ошибался в отношении косвенного расширения (не часть моего вопроса). Я написал 'l_ls = $ {log [log_server]}; l_ls = $ {!l_ls} ', где я должен был сбросить фигурные скобки. – sastorsl

0

Представляя свой собственный ответ. Я ожидаю некоторой здоровой критики :-) Однако основной вопрос заключался в том, как использовать идентичные ассоциативные массивы и циклически перебирать их по единой схеме.

Предложения о том, как добиться того же будет очень цениться:

#!/bin/bash 
# GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu) from RedHat/CentOS 6.4 
declare -A log_server1 log_server2 
log_server1=([name]="ls1" [user]="user") 
log_server2=([name]="ls2" [user]="user") 

declare -A clog1 clog2 clog3 
clog1=([log_server]="log_server1" [path]="/my/path1" [file]="log-files" [rpath]="/log/path1/server1/") 
clog2=([log_server]="log_server2" [path]="/my/path2" [file]="log-files" [rpath]="/log/path/server1/") 
clog3=([log_server]="log_server1" [path]="/my/path3" [file]="log-files" [rpath]="/log/path2/server1/") 

for log in ${!clog*} 
do 
    l_ls=$log[log_server] ; l_p=$log[path] ; l_f=$log[file] ; l_rp=$log[rpath] 
    l_ls=${!l_ls} ; l_p=${!l_p} ; l_f=${!l_f} ; l_rp=${!l_rp} 
    r_n=$l_ls[name] ; r_u=$l_ls[user] 
    r_n=${!r_n} ; r_u=${!r_u} 
    echo "Array $log:" 
    cmd=" scp ${l_p}/${l_f}* ${r_u}@${r_n}:${l_rp}" 
    echo "${cmd}" 
done 

Результат:

$./bash-A-Array.sh 
Array clog1: 
    scp /my/path1/log-files* [email protected]:/log/path1/server1/ 
Array clog2: 
    scp /my/path2/log-files* [email protected]:/log/path/server1/ 
Array clog3: 
    scp /my/path3/log-files* [email protected]:/log/path2/server1/ 
Смежные вопросы