1

I'm trying to assign the element of an array to a variable so I can use it later. For example:

constraints=("A" "B" "C" "E" "Q" "P" "S")

constraint=A

... a loop ...

rand=$[$RANDOM % ${#constraints[@]}]

let constraint="${constraints[${rand}]}"

echo $constraint

... end of loop ...

If the array is all numeric values, it works. But if they are strings the echo always outputs 0. Why?

4
  • 1
    I suggest to remove let. Commented Feb 8, 2018 at 20:45
  • 1
    Yup. let makes your operation arithmetic. All the strings A, B, C, E, Q, P and S evaluate to arithmetic 0. Commented Feb 8, 2018 at 20:46
  • 1
    BTW, $[ ... ] is 1970s-era math syntax; on modern (post-1991-POSIX-sh) shells, use $(( )) instead of either that or let. Commented Feb 8, 2018 at 20:48
  • As another aside -- it's unusual for this to matter ($RANDOM isn't the typical choice if you're deciding a lottery or generating keys to encrypt military secrets, after all), but if ${#constraints[@]} doesn't divide evenly into 32768, then the "random" choice being made here isn't quite fairly weighted. If in a case where this matters, you'll want to compare the randomly-chosen value to see if it's greater than $(( 32768 - (32768 % ${#constraints[@]}) )) and pick a different random number until that isn't true. Commented Feb 8, 2018 at 21:05

2 Answers 2

4

let is only for arithmetic operations. Your strings have no numeric value (unless they name variables which themselves have numeric values), so they all evaluate to 0 in that context.

Make it:

constraint="${constraints[${rand}]}"

...with no let.


In context, this might look like:

constraints=(A B C E Q P S)
rand=$(( RANDOM % ${#constraints[@]} ))
constraint=${constraints[${rand}]}
echo "$constraint"

Note:

  • See the bash-hackers' wiki page on obsolete syntax for discussion of $[ ] and let. Neither is good form in modern scripting.
  • Quotes are not needed (though it's safe to use them, and good practice to do so whenever unsure!) on items that parse unambiguously to a single word during an assignment, as both string-splitting and glob expansion are turned off by default in this context.
  • Quotes are needed for echo $var if the values themselves, or the value of the IFS variable, are unknown or not controlled. See BashPitfalls #14.
Sign up to request clarification or add additional context in comments.

Comments

2

Get rid of the "let."

constraints=("A" "B" "C" "E" "Q" "P" "S")
constraint=A
rand=$[$RANDOM % ${#constraints[@]}]
constraint="${constraints[${rand}]}"
echo $constraint

1 Comment

If you're going to duplicate the entirety of the code, you might want to clean up the other bad practices (missing quotes, use of deprecated $[ ] syntax, etc).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.