【问题标题】:Iterate over several associative arrays迭代几个关联数组
【发布时间】:2013-12-17 06:47:55
【问题描述】:

对于我当前的用例,我正在创建一个 scp 脚本,它将日志文件从一台服务器复制到一台或多台其他服务器。

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

我希望能够在 bash(第 4 版)中使用关联数组(数组)进行日志文件配置,并通过将它们的名称放入索引数组来循环所有 A.数组。

但我很难理解如何使用变量作为 A. Array 的 name 来引用命名的 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

【问题讨论】:

    标签: bash bash4


    【解决方案1】:

    你可以用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_serverpathfilerpath 与键 log1log2 和 @987654332 @?如:

    #!/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
    

    【讨论】:

    • Hell-lo... 我环顾四周很长一段时间,但这个解决方案并不容易 - 因此你的结论 - 丑陋 - 是有效的。我会说,这对其他人来说不太容易阅读......
    • 您对解决此特定问题的其他方法的建议很有趣。尽管如此,您的初始答案以更一般的方式回答了我关于关联数组和循环多个数组的问题。如您所见,我还在为我的日志服务器主机定义使用关联数组,它也必须被引用。我几乎要得出结论:不是这项工作的工具,但它是一个有趣的 bash 冒险。
    • 我知道我在间接扩展方面出了什么问题(不是我的问题的一部分)。我写了l_ls=${log[log_server]} ; l_ls=${!l_ls} 我应该把大括号放下的地方。
    【解决方案2】:

    提出我自己的答案。 我期待一些健康的批评:-) 然而,主要问题是如何使用相同的关联数组,并以统一的方式循环它们。

    将不胜感激有关如何实现相同目标的建议:

    #!/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* user@ls1:/log/path1/server1/
    Array clog2:
       scp /my/path2/log-files* user@ls2:/log/path/server1/
    Array clog3:
       scp /my/path3/log-files* user@ls1:/log/path2/server1/
    

    【讨论】:

      猜你喜欢
      • 2016-01-09
      • 1970-01-01
      • 1970-01-01
      • 2011-12-02
      • 2012-07-07
      • 2012-06-19
      • 2011-03-07
      • 2019-05-11
      相关资源
      最近更新 更多