简体   繁体   中英

Store output of a remote ssh command to a local variable in a loop

I try to run a command for a list of hosts and then store the output in a variable in a loop. I also created an array to associate ip/hostname as my command will only accept IP address as an argument but I want to use hostname and channel name in variable name. My code looks something like:

#!/bin/bash
IP="10.0.0.1 10.0.0.2 10.0.0.3 10.0.0.4 10.0.0.5"
CHANNEL="1 2 3 " 
USERNAME="username" 
SCRIPT_HOST="myscript_host" 
HOME_DIR="/home/myuser" 
SCRIPT_DIR=$HOME_DIR/scripts 
COMMAND="sudo /path_to_my_remote_script" 
SSH="ssh -t -o ConnectTimeout=10 -l $USERNAME"

declare -A array
array[10.0.0.1]="host1"
array[10.0.0.2]="host2"
array[10.0.0.3]="host3"
array[10.0.0.4]="host4"
array[10.0.0.5]="host5"

for ip in ${IP} ; do
for channel in ${CHANNEL} ; do

my_variable_name_$(${array[$($ip)]})_$c=$($SSH "$COMMAND -i $ip |grep -i \"ipv4 count\"|awk {print \$4}'") 

echo my_variable_name_$(${array[$($ip)]})_$c
done;done

When I execute my script I receive an error message like:

./test_array.sh: line 20: 10.0.0.1: command not found ./test_array.sh: line 20: array: bad array subscript

I can guess it's a syntax error but can't figure out. I appreciate any help.

I'd rewrite that as

declare -A array
array[10.0.0.1]="host1"
array[10.0.0.2]="host2"
array[10.0.0.3]="host3"
array[10.0.0.4]="host4"
array[10.0.0.5]="host5"

channels="1 2 3"
script=/path_to_my_remote_script
cmd=(ssh -t -o ConnectTimeout=10 -l username myscript_host)

for ip in "${!array[@]}" ; do
    for channel in $channels ; do
        varname=my_variable_name_${array[$ip]}_$channel
        echo $varname

        remote_script="sudo $script -i $ip | awk -v IGNORECASE=1 '/ipv4 count/ {print \$4}'"
        out=$( "${cmd[@]}" "$remote_script" )

        declare "$varname=$out"
    done
done
  • the declare command can assign to dynamically created variable names without having to use eval
  • you don't need to store the array keys in a separate variable
  • storing commands in arrays is more robust ( ref )
  • if you're calling awk , you don't need to use grep first
  • in my opinion, too many variables can actually reduce readability

On second thought, I'd use another array to store the output, using a pseudo-multi-dimensional key:

declare -A my_variable_name
for ip in "${!array[@]}" ; do
    for channel in $channels ; do
        remote_script="sudo $script -i $ip | awk -v IGNORECASE=1 '/ipv4 count/ {print \$4}'"
        my_variable_name[$ip,$channel]=$( "${cmd[@]}" "$remote_script" )
    done
done

In this line

my_variable_name_$(${array[$($ip)]})_$c= ...

the $(${array{...}}) syntax is the issue. Essentially the $(...) wrapping the array is trying to call a command. Remove the $( and corresponding ) . Likewise in the echo statement below that.

You have to run this through eval and to avoid complicated/unreadable statements I would use a temporary variable:

vname=my_variable_name_${array[$ip]}_$c
tmp=$($SSH ...)
eval $vname=\$tmp

To see what's going on, you can add a

set -x

before the statements or call it as bash -x your-script

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