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).

  • 1
    Please consider, in the future, generating a [Minimal, Complete, Verifiable Example](http://stackoverflow.com/help/mcve) 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. – Charles Duffy Oct 20 '16 at 15:30
  • ...also, there are [a bunch of prior questions here](https://www.google.com/search?q=site%3Astackoverflow.com+bash+pass+arrays+to+function&oq=site%3Astackoverflow.com+bash+pass+arrays+to+function&aqs=chrome..69i57j69i58.5983j0j4&sourceid=chrome&ie=UTF-8) 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). – Charles Duffy Oct 20 '16 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 http://stackoverflow.com/questions/1063347/passing-arrays-as-parameters-in-bash – Charles Duffy Oct 20 '16 at 15:34

1 Answers1

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[@]"
Roland
  • 7,525
  • 13
  • 61
  • 124
OrangesV
  • 322
  • 1
  • 2
  • 9
  • 2
    try `arr1=( "item one" "item two" "item three" )` to see the problem with `${arr1[@]}`, as opposed to the correct `"${arr1[@]}"`. – Charles Duffy Oct 20 '16 at 15:26
  • 2
    ...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. – Charles Duffy Oct 20 '16 at 15:27
  • 2
    ...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. – Charles Duffy Oct 20 '16 at 15:29