Mannix
Mannix

Reputation: 431

BASH, passing multi-item variable to function

I have a function:

function checkConn()
{
    RET=0
    echo "in function: ${2}"
    echo
    for i in `cat ${1}`
    do
        for p in ${2}
        do
            if nc -dzw 2 ${i} ${p}  2>&1 >/dev/null

and so on.

In the "main" body of the script, I have the following:

PORTS='22 161 162 1521'
checkConn ${FILE} ${PORTS}

FILE is the name of a file which contains a list of IPs.

When I pass PORTS to the function, only the 1st item gets passed. I also tried it with double-quotes.

I put that "echo" statement to confirm. It only shows the first item in PORTS, which is 22.

How can I pass all the ports to this function, and then loop through each one?

Upvotes: 0

Views: 65

Answers (2)

Inian
Inian

Reputation: 85550

Multiple syntax violations and outdated constructs, you probably need something like,

function checkConn() {
    # define variables as local unless you are using it beyond the scope
    # of the function and always lower-case variable names 
    local ret=0
    printf "%s\n" "$2"

    # Splitting the string into an array so that it can be accessed 
    # element wise inside the loop. The -a option in read stores the  
    # elements read to the array
    read -ra portList <<<"$2"     

    # Input-redirection of reading the file represented by argument $1
    # representing the file name. The files are read one at a time    
    while IFS= read -r line; do
        # Array values iterated in a for-loop; do the action
        # for each value in the port number
        for port in "${portList[@]}"; do
            if nc -dzw 2 "$line" "$port"  2>&1 >/dev/null; then
                printf "%s %s\n" "$line" "$port"
                # Your rest of the code
            fi
        done
    done < "$1"
}

and call the function as

ports='22 161 162 1521'
filename="file"
checkConn "$filename" "$PORTS"

Upvotes: 1

Charles Duffy
Charles Duffy

Reputation: 295288

Best practice is to pass the list of ports as individual arguments, each with their own argv entry -- like so:

checkConn() {
  file=$1; shift  ## read filename from $1, then remove it from the argument list

  while IFS= read -r address; do
    for port; do  ## we shifted off the filename so this only iterates over ports
      if nc -dzw 2 "$address" "$port" </dev/null >/dev/null 2>&1; then
        echo "$address $port OPEN"
      else
        echo "$address $port CLOSED"
      fi
    done
  done <"$file"
}

file=addrs.txt
ports=( 22 161 162 1521 )
checkConn "$file" "${ports[@]}"

Notes:

  • The function keyword is not actually required for use to define a function; it makes your code incompatible with POSIX sh, but provides no benefit over the portable syntax. Avoid it.
  • The while IFS= read -r idiom is described in detail in BashFAQ #1. Also see Don't Read Lines With For.
  • Arrays, as used in the ports=( ... ) and "${ports[@]}" syntax, are described in the BashGuide.

Upvotes: 2

Related Questions