0

I am unclear what I am doing wrong here or is there some type of bash issue?

I am declaring some static sting arrays and interactively building up another array of string values, all to be passed to a bash function. I get corruption of the array values it seems inside the function itself.

add_firewall_rich_rules() {
  node_ips="${1}"
  swarm_tcp_ports="${2}"
  swarm_udp_ports="${3}"
  echo "in: ${node_ips[@]}"
  echo "in: ${swarm_tcp_ports[@]}"
  echo "in: ${swarm_udp_ports[@]}"
  for ip in "${node_ips[@]}"
  do
        for tcp_port in "${swarm_tcp_ports[@]}"
        do
                rule="'rule family=\"ipv4\" source address=\"$ip\" port protocol=\"tcp\" port=\"$tcp_port\" accept'"
                cmd="firewall-cmd --permanent --zone=public --add-rich-rule=$rule"
                echo "$cmd"
        done
        for udp_port in "${swarm_udp_ports[@]}"
        do
                rule="'rule family=\"ipv4\" source address=\"$ip\" port protocol=\"udp\" port=\"$udp_port\" accept'"
                cmd="firewall-cmd --permanent --zone=public --add-rich-rule=$rule"
                echo "$cmd"
        done
  done
}

declare -a swarm_tcp_ports=('2377' '7946' '4789' '8500' '4000')
declare -a swarm_udp_ports=('2377' '7946' '4789')
declare -a node_ips=()
echo "init: ${node_ips[@]}"
echo "init: ${swarm_tcp_ports[@]}"
echo "init: ${swarm_udp_ports[@]}"
node_ip=""
last_node_ip=""
while read -e -p "Enter ip of additional node in the cluster (hit enter twice to stop adding values): " -i "`echo $node_ip |sed 's/[^.]*$//'`" node_ip; do
  if [ "$node_ip" == "$last_node_ip" ]; then
    break
  fi
  if [[ $node_ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
    node_ips=("${node_ips[@]}" $node_ip)
  else
    echo "hit return again to stop adding values"
  fi
  last_node_ip=$node_ip
  echo "${swarm_tcp_ports[@]}"
done

if [ "${#node_ips[@]}" -gt 0 ]; then
  echo "out: ${node_ips[@]}"
  echo "out: ${swarm_tcp_ports[@]}"
  echo "out: ${swarm_udp_ports[@]}"
  add_firewall_rich_rules ${node_ips[@]} ${swarm_tcp_ports[@]} ${swarm_udp_ports[@]}
fi

From the Terminal:

# ./firewall_add_rich_rule.sh 
init: 
init: 2377 7946 4789 8500 4000
init: 2377 7946 4789
Enter ip of additional node in the cluster (hit enter twice to stop adding values): 192.168.1.105
2377 7946 4789 8500 4000
Enter ip of additional node in the cluster (hit enter twice to stop adding values): 192.168.1.106
2377 7946 4789 8500 4000
Enter ip of additional node in the cluster (hit enter twice to stop adding values): 192.168.1.
hit return again to stop adding values
2377 7946 4789 8500 4000
Enter ip of additional node in the cluster (hit enter twice to stop adding values): 192.168.1.
out: 192.168.1.105 192.168.1.106
out: 2377 7946 4789 8500 4000
out: 2377 7946 4789
in: 192.168.1.105 192.168.1.106
in: 192.168.1.106 7946 4789 8500 4000
in: 2377 7946 4789
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.105" port protocol="tcp" port="192.168.1.106" accept'
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.105" port protocol="tcp" port="7946" accept'
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.105" port protocol="tcp" port="4789" accept'
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.105" port protocol="tcp" port="8500" accept'
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.105" port protocol="tcp" port="4000" accept'
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.105" port protocol="udp" port="2377" accept'
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.105" port protocol="udp" port="7946" accept'
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.105" port protocol="udp" port="4789" accept'
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.106" port protocol="tcp" port="192.168.1.106" accept'
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.106" port protocol="tcp" port="7946" accept'
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.106" port protocol="tcp" port="4789" accept'
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.106" port protocol="tcp" port="8500" accept'
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.106" port protocol="tcp" port="4000" accept'
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.106" port protocol="udp" port="2377" accept'
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.106" port protocol="udp" port="7946" accept'
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.106" port protocol="udp" port="4789" accept'

It seems like the first element from the first array passed into the function is replacing the first element of the next array passed after the function call is made (and i have noticed sometimes the next array as well but not this time).

3
  • 1
    Please consider, in the future, generating a Minimal, Complete, Verifiable Example that has only the smallest amount of code needed to reproduce a problem. In this case, that could probably be just a few lines, with nothing related to firewall rules at all. It should be possible for a reader to determine what the problem is at a glance -- right now, you're giving the current output, but not explaining how that output differs from desired/expected output, leaving it as work for the reader to dig into your code's intent. Commented Oct 20, 2016 at 15:30
  • ...also, there are a bunch of prior questions here about passing arrays into functions, and it's not at present immediately obvious to a casual reader what distinguishes this from any of them (ie. why it's not duplicate at the core). Commented Oct 20, 2016 at 15:34
  • ...if the currently-given answer is in fact responsive to your question, f/e, that would mean that you're duplicative of stackoverflow.com/questions/1063347/… Commented Oct 20, 2016 at 15:34

1 Answer 1

2

When you pass your arrays to the function, it expands the values.

arr1=( "1" "2" "3" )
arr2=( "a" "b" "c" )

someFunc "${arr1[@]}" "${arr2[@]}"

#same as someFunc "1" "2" "3" "a" "b" "c" "d"

So in your function you should take the name of the arrays rather than expanding them and declaring them as a new array inside your functions.

arrayTest(){
    declare -a localArr1=("${!1}")
    declare -a localArr2=("${!2}")

    //process arrays
}

arr1=( "1" "2" "3" )
arr2=( "a" "b" "c" )

arrayTest "arr1[@]" "arr2[@]"
Sign up to request clarification or add additional context in comments.

3 Comments

try arr1=( "item one" "item two" "item three" ) to see the problem with ${arr1[@]}, as opposed to the correct "${arr1[@]}".
...and consider avoiding the function keyword, which is needlessly incompatible with POSIX sh while having no advantages over the standards-compliant function definition syntax (which is just arrayTest() {, as opposed to just function arrayTest() {). Obviously the rest of the code is incompatible here, but no point in encouraging habits or idioms that make code nonportable without compensating advantages.
...also, for newer versions of bash (4.3), consider using namevars: local -n localArr1=$1, there; with that usage, changes to the array made within the function will be reflected outside it, as opposed to being a unidirectional pass-in only.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.