2

I'm starving trying to make the following thing work:

#!/bin/bash
MARCOMIN=1
MARCOMAX=3
ENZOMIN=1
ENZOMAX=3
GIOVANNIMIN=1
GIOVANNIMAX=3
VALUEMARCO=12
VALUEGIOVANNI=4
VALUEENZO=12

for i in MARCO ENZO GIOVANNI; do
        echo $$iMIN is $i\'s MIN
        echo $$iMAX is $i\'s MAX
        echo $VALUE$i is $i\'s VALUE
done

exit 0

It doesn't writes macro as I'd like, though.

me@myhost:~$ bash test.sh
20341iMIN is MARCO's MIN
20341iMAX is MARCO's MAX
MARCO is MARCO's VALUE
20341iMIN is ENZO's MIN
20341iMAX is ENZO's MAX
ENZO is ENZO's VALUE
20341iMIN is GIOVANNI's MIN
20341iMAX is GIOVANNI's MAX
GIOVANNI is GIOVANNI's VALUE

Obviously this is only one of my test. I tried many different ways of writing macros this way but I can't fix it. Found many similar questions here and on SO, but none matched my case.

bash -x test.sh follows:

+ MARCOMIN=1
+ MARCOMAX=3
+ ENZOMIN=1
+ ENZOMAX=3
+ GIOVANNIMIN=1
+ GIOVANNIMAX=3
+ VALUEMARCO=12
+ VALUEGIOVANNI=4
+ VALUEENZO=12
+ for i in MARCO ENZO GIOVANNI
+ echo 21466iMIN is 'MARCO'\''s' MIN
21466iMIN is MARCO's MIN
+ echo 21466iMAX is 'MARCO'\''s' MAX
21466iMAX is MARCO's MAX
+ echo MARCO is 'MARCO'\''s' VALUE
MARCO is MARCO's VALUE
+ for i in MARCO ENZO GIOVANNI
+ echo 21466iMIN is 'ENZO'\''s' MIN
21466iMIN is ENZO's MIN
+ echo 21466iMAX is 'ENZO'\''s' MAX
21466iMAX is ENZO's MAX
+ echo ENZO is 'ENZO'\''s' VALUE
ENZO is ENZO's VALUE
+ for i in MARCO ENZO GIOVANNI
+ echo 21466iMIN is 'GIOVANNI'\''s' MIN
21466iMIN is GIOVANNI's MIN
+ echo 21466iMAX is 'GIOVANNI'\''s' MAX
21466iMAX is GIOVANNI's MAX
+ echo GIOVANNI is 'GIOVANNI'\''s' VALUE
GIOVANNI is GIOVANNI's VALUE
+ exit 0
Marco
  • 418
  • $$ expands to the PID of the running process, which is why you're seeing those numerical prefixes. If you want to do what it is you appear to be trying for, you might have to look into using eval. – DopeGhoti Aug 24 '17 at 19:32
  • 1
    It would be a lot easier, much less error-prone, and probably clearer to instead use arrays with named-constant subscripts or (in bash) even associative arrays with actual names as subscripts. Holding and accessing multiple values that are semantically similar is exactly what arrays are for. But as it is, dupe https://unix.stackexchange.com/questions/263496/bash-array-with-variable-in-the-name – dave_thompson_085 Aug 27 '17 at 03:31

2 Answers2

3

Bash supports variable indirection:

#!/bin/bash
MARCOMIN=1
MARCOMAX=3
ENZOMIN=1
ENZOMAX=3
GIOVANNIMIN=1
GIOVANNIMAX=3
VALUEMARCO=12
VALUEGIOVANNI=4
VALUEENZO=12

for i in MARCO ENZO GIOVANNI; do
    for j in MIN MAX VALUE; do
        varname="${i}${j}"
        # For VALUE we need reverse order of i and j
        [[ $j = VALUE ]] && varname="${j}${i}"

        printf "%d is %s's %s\n" "${!varname}" "$i" "$j"
    done
done

exit 0

I did a little extra with the inner loop and use of printf in place of echo but the central idea is that given a variable name foo stored in another variable bar you can get the value of $foo by doing ${!bar}.

More: https://stackoverflow.com/questions/8515411/what-is-indirect-expansion-what-does-var-mean

B Layer
  • 5,171
-1

To use a variable expansion within the name of another variable is traditionally accomplished with the eval builtin shell command. This often leads to leaning toothpick syndrome (many backslashes and double escapes), which suggests that there may be a "better" way of accomplishing what you want to do. There are also security issues related to using the eval builtin.

In any case, this is one way to accomplish what you want:

# ...
    eval echo \$${i}MIN is \$i\\\'s MIN
    eval echo \$${i}MAX is \$i\\\'s MAX
    eval echo \$VALUE${i} is \$i\\\'s VALUE
# ...
RobertL
  • 6,780
  • Could you point me in the right direction? Which approach would you use to accomplish this? The for is much more complicated than what I've represented. – Marco Aug 24 '17 at 19:43
  • @Marco, That's difficult to say without knowing more about your application. It appears that a tabular (table) approach might be good. If it's getting too complicated in the shell you may want to look at awk or python . Python especially has very rich data structures. Bash has arrays (as opposed to sh), which are not a shell standard, so I usually go to awk or python before using bash arrays. That's because I write almost all shell scripts to the posix standard as closely as possible (#/bin/sh with /bin/sh --> /bin/dash on Debian and it's derivatives). – RobertL Aug 24 '17 at 20:08
  • The variables at this point of the script are already validated and they are positive decimals or integers, or the script dies before getting to this eval. Do you think it may still be a security concern in this case? Also, consider that the script in production will run as an unprivileged user in a jailed shell. – Marco Aug 25 '17 at 16:46
  • 1
    There are security issues related to using eval because you are not quoting it properly. eval can be used securely, but you have to be very careful. – Gilles 'SO- stop being evil' Aug 26 '17 at 22:26
  • @Gilles, are you saying that the example in this answer is not quoted properly? If so, can you tell why it's improper and/or give a pointer to more info? Thanks. – RobertL Aug 28 '17 at 01:54
  • @RobertL You're using a variable outside of double quotes even though this variable doesn't contain an IFS-separated list of file name wildcard patterns. That's an instant fail. – Gilles 'SO- stop being evil' Aug 28 '17 at 11:37