【问题标题】:Store output of a remote ssh command to a local variable in a loop将远程 ssh 命令的输出存储到循环中的局部变量
【发布时间】:2013-12-10 20:12:54
【问题描述】:

我尝试为主机列表运行命令,然后将输出存储在循环中的变量中。我还创建了一个数组来关联 ip/hostname,因为我的命令只接受 IP 地址作为参数,但我想在变量名中使用主机名和通道名。我的代码看起来像:

#!/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

当我执行我的脚本时,我收到如下错误消息:

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

我可以猜测这是一个语法错误,但无法弄清楚。我很感激任何帮助。

【问题讨论】:

  • 我把它改成了: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;完成但同样的错误。 ./test_array.sh: line 20: 10.0.0.1: command not found ./test_array.sh: line 20: array: bad array subscript
  • 据我所知,它不喜欢赋值的右侧,它将 -i $ip 作为单独的命令,但它应该是 $COMMAND 命令的参数。我想查看一个变量名,例如 my_variable_name_10.0.0.1_1 my_variable_name_10.0.0.1_2 my_variable_name_10.0.0.1_3 等等。

标签: arrays bash for-loop ssh echo


【解决方案1】:

我会改写为

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
  • declare 命令可以分配给动态创建的变量名,而无需使用 eval
  • 您不需要将数组键存储在单独的变量中
  • 在数组中存储命令更加健壮 (ref)
  • 如果您调用awk,则无需先使用grep
  • 在我看来,过多的变量实际上会降低可读性

再想一想,我会使用另一个数组来存储输出,使用伪多维键:

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

【讨论】:

  • 太好了,这个解决方案有效并解决了我的问题。非常感谢。
【解决方案2】:

您必须通过eval 运行它,并且为了避免复杂/不可读的语句,我将使用临时变量:

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

要查看发生了什么,您可以添加一个

set -x

在语句之前或将其称为bash -x your-script

【讨论】:

  • 除了 bash -x SUF1=echo ${array[$ip]} SUF2="$channel" vname=my_variable_name_${SUF1}_${SUF2} tmp=$( $SSH " $COMMAND -i $ip -c $channel |grep -i \"ipv4 count\" |awk '{print \$4}'" ) eval $vname=\$tmp done;done
  • + for ip in '${IP}' + for channel in '${CHANNEL}' ++ echo host1 + SUFFIXE1=host1 + SUFFIXE2=1 + vname=my_variable_name_host1_1 ++ ssh -t - o ConnectTimeout=10 -l 用户名 my_script_host 'sudo /path_to_my_remote_script -i 10.0.0.1 -c 1 | grep -i "ipv4 计数" | awk '\''{print $4}'\''' 它卡在这里,我可以用 ctrl+c 打破它,它会在内部循环中连续执行 3,5 和 7 个值的下一个值。我认为它不喜欢在 SSH 命令中以某种方式转义序列。
  • 您的 ssh 命令中似乎有一个错误的'(几乎在最后)
【解决方案3】:

在这一行

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

$(${array{...}}) 语法是问题所在。本质上,包装数组的$(...) 正在尝试调用命令。删除$( 和对应的)。同样在下面的echo 语句中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-26
    • 1970-01-01
    • 2019-11-14
    • 2022-07-21
    • 2014-05-21
    相关资源
    最近更新 更多