简体   繁体   中英

How to use a variable in a variable?

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

The code below is just an excerpt. The purpose below is to reroute/open for some IPs my (http, ftp, telnet and ssh) ports for/to 3 boxes.

The problem is that I want to use variables in a variable. So --dport ${i}_${j}_port_ext is correctly replaced by fi --dport box0_http_port_ext but is not seen as a variable (of course). Actually, what I want should be --dport $box0_http_port_ext (mind the $ at the beginning)

I tried several things fi --dport ${${i}_${j}_port_ext} or --dport $(${i}_${j}_port_ext) but that is 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 it is an excerpt and thus not complete.
The question is: how to code --dport $box0_http_port_ext by making use of $i for box0 and $j for http . Keeping in mind that $i also can be box1/box2 and $j also can be replaced by ftp/telnet/ssh .

You can do it using an Indirect Variable Reference (See http://tldp.org/LDP/abs/html/bashver2.html#EX78 )

This is available in Bash Version 2 and above, using a ! before the variable name, inside the ${ } .

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

In the above example $name returns the sting box0_http_port_ext , which is the name of the initial variable. This is equivalent to ${name}. The ! operator evaluates the string to its right side as a variable name, and returns the value that is stored in the variable. So ${!name} returns the value of ${box0_http_port_ext} which is hello1 .

Unfortunately bash does not support multi-dimensional arrays, but this trick can be used instead.

The difference from the other answer is that $i_$j_port_ext is changed to ${i}_${j}_port_ext so that bash knows where the name of the variable ends.

Try this:

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

Note the ! inside the ${}

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

请尝试在脚本中转义_字符

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

thanks you helped me a lot.

BTW, I did notice the difference between fi $name and {!name}. $name gives the name of the variable, where ${!name} the contents of the variable gives. Is that the only explanation?

Regarding the (good) comments to my question irt the above mentioned excerpt, this is working 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM