0

How do I create n variables in shell scripts without explicitly assigning them? What I mean is something like a loop that creates var1, var2, var3,...,varx, where x is a variable I set earlier, something like:

read x

for ((a=0;a<x;++a)); do
 variable$a=${RANDOM}
done

(Let's ignore the possibility that x might be a string for now. But obviously, this doesn't work. How would one do this?

What I actually want to do, is that each argument I wrote in the command line when I executed the script to become it's own variable ARG1, ARG2... ARGn with ${1}, ${2},..., ${n} as its value, so there will only be as many of these variables, as arguments were set.

slm
  • 363,520
  • 117
  • 767
  • 871
iamAguest
  • 483
  • 1
  • 6
  • 17

4 Answers4

2

It looks like you want to use an array:

read x

for (( a=0; a<x; ++a)); do
   variable[a]=$RANDOM
done

printf 'First value is %s\n' "${variable[0]}"

printf 'All values (one by one): %s\n' "${variable[@]}"
printf 'All values (as one string): %s\n' "${variable[*]}"

For the second part of your question:

arg=( "$@" )

printf 'First command line argument: %s\n' "${arg[0]}"

Note also that you can easily loop over all command line arguments (or whatever happens to be in $@) without storing them anywhere special:

for arg do
    printf 'Got command line argument: %s\n' "$arg"
done
Kusalananda
  • 320,670
  • 36
  • 633
  • 936
  • But isn't an array just one variable but with multiple values? Would that work for what I'm trying to do? (assign each argument as it's own variable) – iamAguest Aug 22 '18 at 09:12
  • 1
    @iamAguest How would you go about using these multiple variables? You would end up with _very_ messy code if you tried to create multiple variables. An array is the proper way to store an indeterminate amount of separate values in any programming language. – Kusalananda Aug 22 '18 at 09:14
  • @iamAguest, is there some essential difference? If you would name them `var1`, `var2` etc., you might as well name them `var[1]`, `var[2]` etc. The workarounds for not using arrays are seriously ugly. – ilkkachu Aug 22 '18 at 09:20
  • Ah I see, that's really cool, but then, how would I go about doing arithmetic with every value in the array? So something I actually wanted was to have the arguments for the script be all integers, and I would be able to add them all together, something like argtotal=$((arg1+arg2+arg3+...+argn)); echo "$argtotal" – iamAguest Aug 22 '18 at 09:26
  • @iamAguest That particular question has been asked a number of times before. See e.g. [How do I create a bash script that sums any number of command line arguments?](https://unix.stackexchange.com/q/98907) – Kusalananda Aug 22 '18 at 09:27
  • @iamAguest, see what [BashGuide has to say on Arrays](https://mywiki.wooledge.org/BashGuide/Arrays) and [my answer to another related question](https://unix.stackexchange.com/a/413455/170373). It's much _easier_ to loop over an array, than it is to list the similarly-named-but-independent variables (with an array, you don't need to know how many elements it has) – ilkkachu Aug 22 '18 at 09:40
1

Try this,

read x

for ((a=0;a<x;++a)); do
 declare -i variable$a=${RANDOM}
done

declare command permits assigning a value to a variable in the same statement as setting its properties.

Siva
  • 9,017
  • 8
  • 56
  • 86
0

You need to eval the assignment (but to use an array would be better).

#!/bin/bash -vx

read x
for ((a=0;a<x;++a)); do
   eval variable$a=${RANDOM}
done

From man bash

eval [arg ...]
    The args are read and concatenated together into a single command. 
    This command is then read and executed by the shell, and its exit 
    status is returned as the value of eval.
andcoz
  • 16,830
  • 3
  • 38
  • 45
  • In this case, `$a` must be a number, so it can't contain any extra expansions (which `eval` would process), so you're sort of safe. But really, if you're running in Bash, why would you ever use `eval` instead of an array in a simple case like this? The mess it potentially produces is just too big. – ilkkachu Aug 22 '18 at 09:23
  • @ilkkachu I agree that it is a weak solution. But, for example, I used this to initialize some configuration variables, reading a json file (from a remote service) without knowing the needed variable names (to prepare the environment to a legacy software). I remember I needed a lot of checks to avoid word splitting. – andcoz Aug 22 '18 at 09:30
  • Yeah, _that_ would be different. Though as another answer reminds, even that could be done with `typeset` (or `declare`) instead of `eval`, e.g. `name=foo; value=bar; typeset "$name=$value"; echo $foo` prints `bar`. – ilkkachu Aug 22 '18 at 09:36
  • @ilkkachu, except that `declare`/`typeset` also have the side effect of reducing the scope of the variable. – Stéphane Chazelas Aug 22 '18 at 11:23
  • 1
    Note that there is a command injection vulnerability here, the same as in all the other answers, because `$x` is evaluated as an arithmetic expression in `for ((...))`, not because of `eval`. Try for instance `echo 'a[$(uname>&2)0]' | bash -c 'read x; for ((i = 0; i < x; i++)); do : ;done'`. By the way `declare`/`typeset` (even `read` in `bash`) can introduce ACEs the same as `eval` (not here as the content of `$a` is controller). They do also evaluate code. – Stéphane Chazelas Aug 22 '18 at 11:34
0

How about (recent shell needed)

 for ((a=0;a<x;++a))
   do  read variable$a <<<${RANDOM}
   done
RudiC
  • 8,889
  • 2
  • 10
  • 22