How do I use a variable in a variable?

I am editing / extending my firewall bash script on a dedicated ubuntu server.

The code below is just an excerpt. The goal below is to redirect / open for some IP addresses my (http, ftp, telnet and ssh) ports for / up to 3 blocks.

The problem is I want to use variables in a variable. So it is --dport ${i}_${j}_port_ext

correctly replaced with fi --dport box0_http_port_ext

, but not treated as a variable (of course). In fact, I want to be --dport $box0_http_port_ext

(mind $

at the beginning)

I tried several things fi --dport ${${i}_${j}_port_ext}

or --dport $(${i}_${j}_port_ext)

, but it's not good.

box0_http_port_ext="8080"
box0_ftp_port_ext="21"
box0_telnet_port_ext="23"
box0_ssh_port_ext="22"
#
allow_box0_http_port_ip="1.2.3.4 99.98.97.96 55.56.57.58"
allow_box0_ftp_port_ip="1.2.3.4 55.56.57.58"
allow_box0_telnet_port_ip="55.56.57.58"
allow_box0_ssh_port_ip="1.2.3.4"
#
for i in box0 box1 box2
do
  for j in http ftp telnet ssh
  do   
    for ips in $allow_${i}_${j}_port_ip
    do
      $IPTABLES -t nat -A PREROUTING -p tcp -i $LAN_IFACE -s $ips --dport ${i}_${j}_port_ext -j DNAT --to-destination ${i}_ip:${i}_${j}_port_int
    done
  done
done

      

Please do not look at the code, because this is an excerpt and therefore not complete.
The question arises: how to encode --dport $box0_http_port_ext

using $i

for box0 and $j

for http. Bearing in mind that $i

it can also be box1 / box2 and $j

can also be replaced with ftp / telnet / ssh.

+3


source to share


4 answers


You can do this using the Indirect Variable link (see http://tldp.org/LDP/abs/html/bashver2.html#EX78 )

This is available in Bash version 2 and above by using !

before the variable name inside ${ }

.

name=${i}_${j}_port_ext
echo ${!name}

      

Working example:

#!/bin/bash
i=box0
j=http

box0_http_port_ext="hello1"
box2_telnet_port_ext="hello2"

name=${i}_${j}_port_ext
echo "varname: $name   value: ${!name}"

i="box2"
j="telnet"
name="${i}_${j}_port_ext"
echo "varname: $name   value: ${!name}"

      



Output

varname: box0_http_port_ext   value: hello1
varname: box2_telnet_port_ext   value: hello2

      

The above example $name

returns sting box0_http_port_ext

, which is the name of the initial variable. This is equivalent to $ {name}. The operator !

evaluates the string on the right-hand side as a variable name and returns the value that is stored in the variable. Therefore, it ${!name}

returns a value ${box0_http_port_ext}

that is hello1

.

Unfortunately Bash does not support multidimensional arrays, but this trick can be used instead.

The difference from the other answer is what $i_$j_port_ext

changes to ${i}_${j}_port_ext

so that Bash knows where the variable name ends.

+5


source


Try the following:

varname=${i}_${j}_port_ext
... --dport ${!varname} ...

      



Note! inside${}

Edited: good point from @ user000001 about restricting i / j variable names.

+2


source


Please try to escape the character _

in your script

--dport $i\_$j\_port\_ext

      

0


source


Thank you, you helped me a lot.

By the way, I noticed a difference between fi $ name and {! name}. $ name gives the name of the variable, where $ {! name} contains the contents of the variable. Is this the only explanation?

Regarding the (good) comments on my question irt the above excerpt, this works for me:

for i in box0 box1 box2
do
  for j in http ftp telnet ssh
  do
    ALLOWED_IPS=allow_${i}_${j}_port_ip
    for ips in ${!ALLOWED_IPS}; do
    do
      PORT_EXT=${i}_${j}_port_ext; PORT_INT=${i}_${j}_port_int; IP=${i}_ip
      $IPTABLES -t nat -A PREROUTING -p tcp -i $LAN_IFACE -s $ips --dport ${!PORT_EXT} -j DNAT --to-destination ${!IP}:${!PORT_INT}
    done
  done
done

      

0


source







All Articles