击:使用一个变量作为数组名 [英] Bash: Use a variable as an array name

查看:129
本文介绍了击:使用一个变量作为数组名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我解析日志文件和用于与行号和最后一个字段(总时间登录)的每个用户创建关联数组。日志文件的线条看起来是这样的:

I am parsing a log file and creating associative arrays for each user with the line number and the last field (total time logged in). The lines of the log file look like this:

jww3321   pts/2        cpe-76-180-64-22 Mon Oct 18 23:29 - 00:27  (00:58)
jpd8635   pts/1        cpe-74-67-131-24 Mon Oct 18 23:22 - 03:49  (04:26)

第一个字段(jww3321)将数组名和数组将是(1,00:58)中的第一项,接下来会(2,(下一次用户))。为了获得正确的密钥我需要保存列表的长度和添加一个到它时,我的下一个值添加到用户数组。我的code到目前为止是这样的:

Where the first field (jww3321) will be the array name and the first entry in the array will be (1,00:58), the next will be (2,(the next time for user)). In order to obtain the proper keys I need to save the the length of list and add one to it when I add the next value to a user array. My code so far looks like this:

cat lastinfo.txt | while read line
do
    uname=`echo "$line" | awk '{print $1;}'`
    count=`echo "${#$uname[@]}"`
    echo "$count"
done

我一直在使用间接引用尝试,但我坚持这个错误:

I have tried using indirect references but I am stuck with this error:

l8t1: line 7: ${#$uname[@]}: bad substitution

有什么建议?

推荐答案

我不知道我是否正确理解你正在尝试做的,特别是联想的部分(我不能看到一个关联数组是使用),但这个code做什么,我知道你想做的事:

I'm not sure if I understood correctly what you are trying to do, specifically the "associative" part (I can't see where an associative array is used), but this code does what I UNDERSTAND that you want to do:

#!/bin/bash
while IFS=" " read user time; do
    eval "item=\${#$user[@]} ; $user[\$item]=\(\$((\$item + 1)),$time\)"
    [[ "${arraynames[@]}" =~ $user ]] || arraynames[${#arraynames[@]}]=$user
done< <(sed -r 's/^ *([[:alnum:]]*) .*\((.*)\)$/\1 \2/')

for arrayname in ${arraynames[@]}; do
    eval "array=(\${$arrayname[@]})"
    echo "$arrayname has ${#array[@]} entries:"
    for item in ${!array[@]}; do
        echo "$arrayname[$item] = ${array[$item]}"
    done
    echo
done

它从标准输入读取。我已经像这样的例子文件测试吧:

It reads from stdin. I've tested it with an example file like this:


    jww3321   pts/2        cpe-76-180-64-22 Mon Oct 18 23:29 - 00:27  (00:58)
    jpd8635   pts/1        cpe-74-67-131-24 Mon Oct 18 23:22 - 03:49  (04:26)
    jww3321   pts/2        cpe-76-180-64-22 Mon Oct 18 23:29 - 00:27  (01:58)
    jpd8635   pts/1        cpe-74-67-131-24 Mon Oct 18 23:22 - 03:49  (05:26)

输出:


    jww3321 has 2 entries:
    jww3321[0] = (1,00:58)
    jww3321[1] = (2,01:58)

    jpd8635 has 2 entries:
    jpd8635[0] = (1,04:26)
    jpd8635[1] = (2,05:26)

请注意,只有标准的整数索引的阵列中。在bash中,截至目前,在左侧间接数组引用的总是涉及使用评估(uuuuuuhhhh,幽灵般的声音),在右边你可以逃脱 $ {!} 替换和命令替换 $()

Note that only standard integer-indexed arrays are used. In Bash, as of now, indirect array references in the left side always involve using eval (uuuuuuhhhh, ghostly sound), in the right side you can get away with ${!} substitution and command substitution $().

与EVAL经验法则:逃避你想要什么在评估来进行扩展时,不要逃避你想要什么之前 EM> 评估的时间。你什么最终被eval'd无疑是任何时间,使线条和变化的复制评估回声

Rule of thumb with eval: escape what you want to be expanded at eval time, and don't escape what you want to be expanded before eval time. Any time you're in doubt about what ends up being eval'd, make a copy of the line and change eval for echo.

编辑:的回答sarnold的评论,一个办法做到这一点没有EVAL:

edit: to answer sarnold's comment, a way to do this without eval:

#!/bin/bash
while IFS=" " read user time; do
    array=$user[@] array=( ${!array} ) item=${#array[@]}
    read $user[$item] <<< "\($(($item + 1)),$time\)"
    [[ "${arraynames[@]}" =~ $user ]] || arraynames[${#arraynames[@]}]=$user
done< <(sed -r 's/^ *([[:alnum:]]*) .*\((.*)\)$/\1 \2/')

for arrayname in ${arraynames[@]}; do
    array=$arrayname[@] array=( ${!array} )
    echo "$arrayname has ${#array[@]} entries:"
    for item in ${!array[@]}; do
        echo "$arrayname[$item] = ${array[$item]}"
    done
    echo
done

这篇关于击:使用一个变量作为数组名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆