我正在尝试读取成对的文件,如下所示:
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)中做到这一点?
答案 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)
假设:
输入文件:
$ cat kdat
V1#K1.@
V2#K1.@
V3#K2.@,V4#K1.@,V5#K2.@
V1#K3.@
V1#K3.@
V1#K3.@
一个基于sed
和awk
(在bash
和ksh
中都可用的解决方案)的解决方案,其中我们使用属性/值对作为二维索引数组。通过将任意值(在这种情况下为'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
来漂亮地打印输出