6

I have read about specifying "10#", but I don't think it's my case as I am not doing number comparison. I am trying to create an associative array in Bash, and the code worked fine until today (2021-02-08):

dailyData["$today"]="$todayData"

$today is a day in ISO format, $todayData is not relevant.
I am getting the error 2021-02-08: value too great for base (error token is "08").

Why does Bash interpret this date format as a number, where an arbitrary string does the job (associative array key)?
What if I wanted to use just "08" as dictionary key?

muru
  • 69,900
  • 13
  • 192
  • 292
Polizi8
  • 175
  • 2
  • 11

2 Answers2

12

It's because dailyData is being automatically created as indexed array rather than an associative array. From man bash:

An indexed array is created automatically if any variable is assigned to using the syntax name[subscript]=value. The subscript is treated as an arithmetic expression that must evaluate to a number.

The issue goes away if you explicitly declare dailyData as an associative array:

$ declare -A dailyData[2021-02-08]="$todayData"

$ declare -p dailyData
declare -A dailyData=([2021-02-08]="" )
ilkkachu
  • 133,243
  • 15
  • 236
  • 397
steeldriver
  • 78,509
  • 12
  • 109
  • 152
  • Oh thank you, I forgot to use `declare -A` either when adding values or before starting to do so like in @choroba's example. I also noticed that if you use a string as subscript (indexed array) it doesn't fail, but it sets the subscript to "0", eventually replacing older entries – Polizi8 Feb 08 '21 at 12:04
8

I can't reproduce the problem with associative arrays:

#! /bin/bash
declare -A dailyData
today=2021-02-08
todayData=whatever
dailyData["$today"]="$todayData"

But, if I use normal arrays, i.e. declare -a (mind the case!) or no declaration at all, then I'm getting the error you mention. That's because the array index is interpreted as an arithmetic expression, so for 2021-02-07, it was just calculated as 2021 - 2 - 7 = 2012, but for 2021-02-08, the last number in the subtraction is invalid in octal.

choroba
  • 45,735
  • 7
  • 84
  • 110
  • 3
    and that last part of course means that e.g. `2021-03-06` would be taken as exactly the same index as `2021-02-07`, even though they'd seem to work without errors. – ilkkachu Feb 08 '21 at 09:54
  • Thank you, I forgot `declare -A`. Any idea on why if a common word is used as subscript of an indexed array, it is evaluated to 0, without returning any error like "'word' is not a valid expression"? – Polizi8 Feb 08 '21 at 12:10
  • @Polizi8, because it is a valid expression, one that refers to a variable by that name. E.g. `foo=3; echo $((foo+4))` prints 7 in all shells I have, and Bash/ksh/Zsh even do that recursively, so `foo="2*bar"; bar=3; echo $((foo+4))` prints 10. [Bash's manual describes this](https://www.gnu.org/software/bash/manual/html_node/Shell-Arithmetic.html"): "Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax." and "The value of a variable is evaluated as an arithmetic expression when it is referenced." – ilkkachu Feb 08 '21 at 12:31
  • @Polizi8, Actually, that behaviour is kinda scary if you take supposedly numeric values as input from a user. If they enter a name of a variable, they can force your script to use that, even if it's supposed to be something "hidden". Worse, Bash/ksh/Zsh also process any expansions, _including command substitutions_ in array indices, even within variables used in arithmetic. So something like `foo="a[\$(echo surprise >&2)]"; echo $((foo+4))` will run the echo and print `surprise` to stderr. – ilkkachu Feb 08 '21 at 12:36
  • @ilkkachu Yes but I am not talking about a variable: by running `declare -a array[word]="value"`, "value" is associated to index "0", as shown by `echo "${!array[*]}"` and `echo "${array[0]}"`. Why does "word" get converted to "0"? I have never declared "word" or "w", "o", "r", "d" as variables – Polizi8 Feb 08 '21 at 14:13
  • Because in arithmetic expressions, undefined variables are treated as 0s. – choroba Feb 08 '21 at 14:39
  • @Polizi8, yep, I managed to leave out the part you actually asked about... It's like how `$foo` just turns into the empty string if `foo` is not set. In an arithmetic context it just turns to a zero. Regardless of if you want it or not, `word` refers to a variable in your example. – ilkkachu Feb 08 '21 at 20:18