两个while循环行为奇怪,Bash脚本

时间:2014-04-08 00:39:27

标签: bash shell

我是Bash脚本的新手。我编写了一个脚本来帮助我从一堆服务器中使用ssh获取一些信息。第一组设备的IP地址从101到148,另一组从201到210。

#!/bin/bash

BASE=192.168.11
SD_START=101
SD_END=148
HD_START=201
HD_END=210
SD_counter=$SD_START
HD_counter=$HD_START

while [[ $SD_counter -le $SD_END ]]
do 
    ip=$BASE.$SD_counter
    ssh $ip command1
    SD_counter=$(($SD_counter +1))

    if [ "$SD_counter"==148 ]
    then

        while [[ $HD_counter -le $HD_END ]]
        do
            ip=$BASE.$HD_counter

            ssh $ip command2
            HD_counter=$(($HD_counter +1))
        done
    fi 

done > log_SD_HD

echo "Done!"    

但由于某种原因,command1首先在192.168.11.101上执行,然后在ip范围192.168.11.201-192.168.11.210执行command2,这是第二个while循环。 之后,第一个while循环一直持续到结束。 为什么会这样?我希望第一个while循环在第二个while循环之前完成。有人可以指出我做错了吗?

3 个答案:

答案 0 :(得分:2)

没有理由将循环嵌套在您展示的内容中:

#!/bin/bash

BASE=192.168.11
SD_START=101
SD_END=148
HD_START=201
HD_END=210
SD_counter=$SD_START
HD_counter=$HD_START

while [[ $SD_counter -le $SD_END ]]
do 
    ip=$BASE.$SD_counter
    ssh $ip command1
    SD_counter=$(($SD_counter +1))
done> log_SD_HD
while [[ $HD_counter -le $HD_END ]]
do
    ip=$BASE.$HD_counter
    ssh $ip command2
    HD_counter=$(($HD_counter +1))
done>> log_SD_HD

echo "Done!" 

答案 1 :(得分:2)

<强>更新

提示:您始终可以使用#!/bin/bash -x来跟踪和调试脚本。


正如V_Maenolis所展示的那样,使用两个while循环是一个好主意。但是,要回答关于脚本出现问题的问题,请尝试使用

替换

if [ "$SD_counter"==148 ]

if [ "$SD_counter" -gt 148 ]

对我有用。

所以有两个错误

  1. ==运算符之前和之后应该有一个空格,也就是说,使用A == B NOT A==B
  2. 比较SD_counter == 148的逻辑不正确。因为当SD_counter达到148时,你的脚本将进入第二个while循环,你将获得147, 201, ..., 210, 148。使用-gt可以避免此问题。

答案 2 :(得分:2)

@ 0x1cf的回答提供了正确的指针:

[ "$SD_counter"==148 ]没有按预期工作。

具体来说:"$SD_counter"==148基于bash的字符串合成规则,扩展为单字符串文字$SD_counter的值与文字{{{1}连接{1}},生成的字符串文字被视为布尔值。 由于布尔上下文中的非空字符串始终求值为==148,因此true [ "$SD_counter"==148 ]始终求值为true >

除此之外:在bash中你应该使用==而不是[[ ... ]] - 它更强大并提供更多功能。

另请注意(正如@ 0x1cf所说) - 如果使用[ ... ][ ... ] - 使用算术运算符是正确的选择处理数字时[[ ... ]]-eq-ne-lt-le-gt。< / p>

但一般来说,使用-ge表达式 - 算术评估 - 提供更多的数字灵活性 - 请参阅下文。


即使使用算术评估 - (( ... ))您的代码可以大大简化(请参阅(( ... ))中的ARITHMETIC EVALUATION部分):

它允许您使用 C风格的算术和布尔表达式。 如果我们将此与bash的 数组变量结合使用,您的代码可以简化为:

man bash

注意:

  • #!/usr/bin/env bash BASE=192.168.11 START_INDICES=( 101 201 ) END_INDICES=( 148 210 ) COMMANDS=( command1 command2 ) numRanges=${#START_INDICES[@]} for (( range = 0; range < numRanges; ++range )); do cmd=${COMMANDS[range]} for (( i=${START_INDICES[range]}; i<=${END_INDICES[range]}; ++i )); do ip=$BASE.$i ssh $ip $cmd done done > log_SD_HD 表达式DIFFER来自正常的bash分配和条件:

    • 无需使用(( ... ))
    • 引用变量
    • 无需双引号变量引用
    • 您可以在赋值运算符($
    • 周围添加空格
    • 你可以省略关系运算符周围的空格:=可以工作。
  • (( SD_counter==148 ))创建一个包含元素( string1 ... )string1的数组; ...返回数组变量${#arrayVar[@]}的元素数; arrayVar返回带有(${arrayVar[ndx]} - )索引0的元素。

  • 最好避免使用诸如ndx之类的ALL-UPPERCASE变量名称,因为它们可能与环境变量冲突,而环境变量通常都是大写的。