我试图迭代 bash 脚本中关联数组的最后几个条目 - 在本例中是为了总结它们的值。我尝试过以下方法:
SUM="0"
for last_element in $(printf "%s\n" "${!ELEMENTS[@]}" | tail -100); do
ELEMENT_SUM="$(echo "scale=5; $SUM + ${ELEMENTS[$last_elements]}" | bc)"
done
实践中发生的情况是打印$last_element
出整个列表(在本例中为 100 个元素),而不是迭代每个元素 - 因此会${ELEMENTS[$last_elements]}
失败。
${ELEMENTS[-100]}
我尝试了多种方法(例如,包括负索引),但没有成功。我不确定我做错了什么......
任何指示和想法将不胜感激。
谢谢!
答案1
bash 中的关联数组本质上是无序的,因此不存在最后一个元素或最后 100 个元素的概念。
但是,如果想要以伪随机顺序对从数组中提取的 100 个元素的值求和,您可以执行以下操作:
e100=$(printf "%s\n" "${elements[@]}" | tail -n 100)
sum=$(echo ${e100//$'\n'/+} | bc)
echo $sum
第一行用于printf
将关联数组中的 100 个元素存储$elements
到变量中$e100
,并以换行符分隔。
第二行使用echo
bash 参数模式替换将所有换行符更改为+
符号,然后通过管道将其输入bc
以执行计算。结果存储在变量 中$sum
。
顺便说一句,这使用价值观直接关联数组,无需迭代数组的索引。
有更好的方法可以做到这一点,正如老笑话所说的“好吧,如果你想去那里,我不会从这里开始”,bash 并不是任何类型的数据处理的良好起点。使用 awk 或 perl 或 python 或几乎任何非 shell 的东西。
想必您正在使用浮点数,并且已经意识到 bash 只能进行整数算术,因此您正在使用bc
它来解决这个问题。您最好使用一种不需要您解决执行此类基本操作的限制的语言。
答案2
bash 关联数组(您需要最新版本)不支持任意键。它也没有用于对列表进行排序的运算符(您需要它最后的有意义),并且不能进行浮点运算。
在这里,我将使用限制较少的 shell(如 zsh)或适当的编程语言(如 perl)。
#! /usr/bin/perl
use List::Util "sum";
%elements = (
"foo" => 1.213,
"\0\n" => 0x12,
'' => -3,
"bar" => 1e-2
...
);
$sum = sum(map {$elements{$_}} (sort keys %elements)[-100 .. -1]);
#! /bin/zsh -
typeset -A elements
elements=(
foo 1.213
$'\0\n' 0x12
'' -3
bar 1e-2
...
)
set -o extendedglob
sum=$(( ${(@j[ + ])${(@ko)elements}[-100,-1]/(#m)*/$elements[$MATCH]} ))
这些给出了按字典顺序排序的最后 100 个键的元素总和(memcmp()
类似 perl 中的比较,strcoll()
类似 zsh 中的比较)。
对于 zsh,值可以是 zsh 识别的任何算术表达式,但当我们最终构建一个value1 + value2 + ...
供 zsh 求值的表达式时,请注意优先级。
例如,如果value1
isvar = 3
和value2
is 4 || hash[$(some-cmd)]
,最终会进行评估var = 3 + 4 || hash[$(some-cmd)]
(并且some-cmd
将被执行),因此您可能需要确保值被包围,(...)
如果它们不仅仅是数字。