samuel groome
samuel groome

Reputation: 23

Bash elif not being used it seems

Just started looking at bash scripts yesterday and wanted to make a script for work where in I ping different addresses on a network and using ssh keys I login and shutdown mikrotiks/junipers/computers in order. I came up with this and it seems to work for the 'mikrotik' array but not for the 'other' elif statement. I'm testing this by just changing an IP address from the MikroTik array to the 'other' array to trigger the elif but it doesn't seem to do anything. Just goes straight to the else statement.

This is one of my first proper bash scripts and assembled this using other examples, stuck here for some reason.

#!/bin/bash
#first array to make the script turn off the nodes in the order I want.
targets=(
192.168.10.10
192.168.10.11 
192.168.10.2  
192.168.10.1  
192.168.10.3  
192.168.50.21 
192.168.50.3 
192.168.50.20
192.168.50.2  
192.168.50.1  
192.168.50.22 
)
mikrotik=(192.168.10.1 192.168.10.2 192.158.50.1 192.168.50.2 192.168.10.5)  #Mikrotik addresses
other=(192.168.50.3 192.168.10.3 192.168.10.10 192.168.10.11 192.168.50.21 192.168.50.20 192.168.50.22) #other addresses

for target in "${targets[@]}" #For each index of targets do...
    do
    ping -c1 $target > /dev/null  #ping each ip address

    if [[ ($? -eq 0) && (${mikrotik[*]} =~ "$target") ]] #if ping successful and target is within mikrotik array
    then 
        echo "$target mikrotik has replied and will now shutdown"
        ssh $target "system shutdown"
        echo "..................................."

    elif [[ ($? -eq 0) && (${other[*]} =~ "$target") ]]  #if ping successful and target within the juniper or computer array
    then
        echo "$target device has replied and will now shutdown"
        ssh $target "shutdown now"
        echo "..................................."

    else
        echo "$target didn't reply moving onto next target"
        echo "..................................."
    fi
done

Upvotes: 2

Views: 108

Answers (1)

KamilCuk
KamilCuk

Reputation: 141155

$? contains the last command executed. So you do:

command1
if command2 ... $? ...; then    # this command has it's own exit status
                                # and it's nonzero because the body is not executed!
     ...
elif command3 ... $? ...; then  # the __LAST__ command here is command2
                                # $? has the exit status of command2, __not__ command1
     ...
fi

The $? inside elif has the exit status of [[ executed in the first if. Because first if body was not executed, the [[ exited with nonzero exit status - so $? in the elif clause will always be nonzero. Generally, using $? like doing command; if (($?)); then is an antipattern - don't use it. Check the exit value of the command instead - if command; then. You want to check the exit status of ping, so test it with if:

if ping -c1 $target > /dev/null; then

     # those if's could be refactored too to extract common code
     if [[ ${mikrotik[*]} =~ "$target" ]]; then
             name=mikrotik
             command=(system shutdown)
     elif [[ ${other[*]} =~ "$target" ]]; then
             name=device
             command=(shutdown now)
     else
             handle error
     fi
     echo "$target $name has replied and will now shutdown"
     ssh "$target" "${command[@]}"

else
      echo "$target didn't reply moving onto next target"
fi
echo "..................................."

If you really want to store the exit status of command for later use, save it in a temporary variable right after using it, then use that temporary variable.

ping ...
pingret=$?
if ((pingret == 0)); then something; fi

Upvotes: 3

Related Questions