ksh中一个键的多个值

时间:2019-07-12 10:00:43

标签: arrays hashmap ksh associative

我正在尝试读取成对的文件,如下所示:

V1#K1.@
V2#K1.@
V3#K2.@,V4#K1.@,V5#K2
V1#K3.@

我的目标是在删除key<=>pairs之后,以#作为定界符将其存储在'@'中,将值放在#之前,并将键放在#之后示例文件

associate multiple values for one key in array in bash中提到的答案无法实现。 所以我在ksh中以以下方式尝试了它:

#!/usr/bin/ksh

typeset -A arr

while IFS= read -r line;do
    STRIPPED=`echo $line|sed 's/.@//g'`
    OIFS="$IFS"
    IFS=','
    read -A TOKENS <<< "${STRIPPED}"
    IFS="$OIFS"

    for key in ${TOKENS[@]};do
        echo "Token is $key"    
        arr[${i##*#}]=${i%%#*}
        echo "Key: ${key##*#}, Value: ${arr[${key##*#}]}"
    done
done <MYFILE

# Printing key and its values
for i in ${!arr[@]};do
    echo "key: ${i}, value: ${arr[$i]}"
done

但是,这将覆盖键的先前值。它不考虑键的多个值。 有没有办法在ksh(不是bash)中做到这一点?

2 个答案:

答案 0 :(得分:1)

我会这样做,它将多个值存储为逗号分隔的字符串

#!/usr/bin/env ksh

# The `exec` line tells ksh to read from MYFILE _if_ stdin has _not_ been redirected
# This allows you to do:
#    ./script.ksh
#    ./script.ksh < some_other_file
#    some_process | ./script.ksh

[[ -t 0 ]] && exec 0<MYFILE

typeset -A arr

while IFS= read -r line; do
    # greatly simplified tokenization
    IFS=',' read -rA tokens <<< "${line//.*/}"

    for t in "${tokens[@]}"; do
        key=${t%#*}
        val=${t#*#}
        [[ -n ${arr[$key]} ]] && arr[$key]+=,
        arr[$key]+=$val
    done
done

# Printing key and its values
for i in "${!arr[@]}"; do
    echo "key: ${i}, value: ${arr[$i]}"
done

输出

key: V1, value: K1,K3
key: V2, value: K1
key: V3, value: K2

答案 1 :(得分:1)

假设:

  • 输入数据的格式与问题中显示的完全相同(即,无需担心其他/冗长的文本)
  • 示例输入的第3行在第3个属性/值对的末尾缺少“。@”
  • 为演示重复处理,我将复制最后一条输入行几次
  • 该问题没有所需输出的示例,因此我将使用glenn的示例输出
  • (对于输出)没有明确提及任何排序首选项,因此在此我将跳过尝试进行任何类型的排序

输入文件:

$ cat kdat
V1#K1.@
V2#K1.@
V3#K2.@,V4#K1.@,V5#K2.@
V1#K3.@
V1#K3.@
V1#K3.@

一个基于sedawk(在bashksh中都可用的解决方案)的解决方案,其中我们使用属性/值对作为二维索引数组。通过将任意值(在这种情况下为'1')指定为数组值,我们可以消除重复的值。

  • 第一次看到一个(新的)属性/值对,我们创建了数组元素
  • 下次我们看到(相同)属性/值对时,我们只是覆盖了数组元素
  • 处理完输入后,我们发现每个属性/值对都与单个数组元素相关联(即没有重复项)

现在是实际代码:

$ sed 's/,/\n/g;s/.@//g' kdat | awk -F"#" '
{ myarray[$1][$2]=1 }
END { for (i in myarray)
      { delim=""
        printf "key: %s, value: ",i
        for (j in myarray[i])
            { printf "%s%s",delim,j
              delim=","
            }
        printf "\n"
      }
    }
'

key: V1, value: K1,K3
key: V2, value: K1
key: V3, value: K2
key: V4, value: K1
key: V5, value: K2

位置:

  • sed ...:用回车符替换逗号(每个属性/值对在单独的行上;此awk解决方案假定每行一个属性/值对);删除“。@”
  • awk -F"#" ...:使用“#”作为输入定界符来分隔属性对($ 1)和值($ 2)对
  • myarray[$1][$2]=1:创建/覆盖数组($ 1,$ 2)为'1';这是重复项被丢弃的地方
  • for / printf:循环遍历数组索引,使用printf来漂亮地打印输出

几个小提琴:kshbash