私は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
。
2行目は、echo
bash引数パターン置換を使用してすべての改行をシンボルに変更し、計算を実行するために+
パイプに接続します。bc
結果は変数に保存されます$sum
。
ところで、これは価値連想配列を直接使用すると、配列のインデックスを繰り返す必要はありません。
これを行うより良い方法があり、「まあ、そこに行きたいならここで始めない」という古いジョークのように、bashはあらゆる種類のデータ処理のための良い出発点ではありません。 awk、perl、python、シェルではないほとんどすべてを使用してください。
おそらく、あなたは浮動小数点数で作業していて、bashが整数演算しか実行できないことに気づいたので、bc
この問題を解決するためにそれを使用しています。そのような基本的なタスクを実行する際の制限を解決する必要がない言語を使用することをお勧めします。
答え2
bash連想配列(最新バージョンが必要)は任意のキーをサポートしません。また、リストをソートする演算子はありません(必要です)。最後意味あり)浮動小数点演算を実行できません。
ここでは、制限の少ないシェル(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
値を囲むようにできます。(...)