【问题标题】:Convert for loop to while loop in bash script在bash脚本中将for循环转换为while循环
【发布时间】:2021-12-30 03:21:28
【问题描述】:

我有一个for循环如下:

mapfile -t ipLast < SippIPs.txt

echo "   ----  SIPp ----  "
echo "Please give count of SIPps needed to generate calls.."
read -p 'Sipps count starts from: ' start; read -p 'Sipps count ends on: ' end
if [[ -z $start ]] || [[ -z $end ]]; then echo "User pressed ENTER with no input text"; fi

for ((j=$start; j<=$end; j++)); do
        sipps=${j[@]}
        ipList=(${ipLast[sipps-1]})
        if [[ "$end" -eq 0 ]]; then
                echo "No way it cannot end on 0"
                exit
        fi

        echo "    ----  Launching SIPp $sipps ----  "
        sshpass -p "root12" ssh -tt -o StrictHostKeyChecking=no root@$ipList <<EOF1
        pkill -f sipp

        screen -S sipp -d -m bash -c 'cd /usr/local/src/sipp-3.3; ulimit -Hn 65535; ulimit -Sn 65535; ./sipp -i $ipList -mi $ipList -sf HA_demo.xml -inf HA_demo.csv 10.171.0.231:5060 -p 5060 -r 1 -rp 1s -l 1 -m 1 -watchdog_minor_threshold 1500 -watchdog_major_threshold 4000 -watchdog_major_maxtriggers 30 -trace_err -aa -d 350s -oocsn ooc_default -t u1 -trace_screen -skip_rlimit && exec bash'
        exit
EOF1
done

我想将 for 循环转换为 while 循环,以便在给出计数后返回到循环以询问用户是要退出还是继续启动 SIPp。

我的尝试:

mapfile -t ipLast < SippIPs.txt
read -p 'Sipps count starts from: ' start; read -p 'Sipps count ends on: ' end

j=$start
while (j<=$end); do
        sipps=${j[@]}
        ipList=(${ipLast[sipps-1]})
        if [[ "$end" -eq 0 ]]; then
                echo "No way it cannot end on 0"
                exit
        fi

        echo "    ----  Launching SIPp $sipps ----  "
        sshpass -p "root12" ssh -tt -o StrictHostKeyChecking=no root@$ipList <<EOF1
        pkill -f sipp

        screen -S sipp -d -m bash -c 'cd /usr/local/src/sipp-3.3; ulimit -Hn 65535; ulimit -Sn 65535; ./sipp -i $ipList -mi $ipList -sf HA_demo.xml -inf HA_demo.csv 10.171.0.231:5060 -p 5060 -r 1 -rp 1s -l 1 -m 1 -watchdog_minor_threshold 1500 -watchdog_major_threshold 4000 -watchdog_major_maxtriggers 30 -trace_err -aa -d 350s -oocsn ooc_default -t u1 -trace_screen -skip_rlimit && exec bash'
        exit

        j++
EOF1
done

【问题讨论】:

    标签: bash while-loop


    【解决方案1】:

    直接的问题是您需要双 ((...)) 进行算术评估。表达式(j&lt;=$end) 尝试使用来自文件=$end 的输入在子shell 中运行程序j

    此外,在远程主机上执行j++ 显然不会更新本地变量j,即使您修复了语法。你显然想要类似的东西

    j=$start
    while ((j<=$end)); do
        :
        sshpass -p "root12" ssh -tt -o StrictHostKeyChecking=no root@$ipList <<EOF1
            :
    EOF1
        ((j++))
    done
    

    sipps=${j[@]} 的表达式看起来很奇怪; j 不是数组。

    无论如何,这里没有特别需要从for 循环切换到while 循环;如果用户表示他们想停止循环,则只需 break 退出循环。

    screen 的恶作剧看起来可能是您做错了,但如果没有关于“它”的更多信息,我们很难建议任何更改。 exec bash 是可疑的;这段代码实际上应该完成什么?

    exit 在脚本末尾是多余的;当 shell 完成执行脚本时,它总是exit。或许评论Pass commands as input to another command (su, ssh, sh, etc)

    与往常一样,您将希望避免使用read -p 来接收参数;一个更好的设计是让调用者指定扫描范围的开始和结束作为命令行参数。那么start 将是$1end 将是$2(假设您没有其他命令行处理)。

    【讨论】:

      【解决方案2】:

      这就是我要找的东西:

      while :
              mapfile -t ipLast < SippIPs.txt
              read -p 'Sipps count starts from: ' start; read -p 'Sipps count ends on: ' end
              if [[ -z $start ]] || [[ -z $end ]]; then echo "User pressed ENTER with no input text"; fi
              echo "   ----  SIPp ----  "
              echo "Please give count of SIPps needed to generate calls.."
      do
              for ((j=$start; j<=$end; j++)); do
                      sipps=${j[@]}
                      ipList=(${ipLast[sipps-1]})
                      if [[ "$end" -eq 0 ]]; then
                              echo "No way it cannot end on 0"
                              exit
                      fi
      
                      echo "    ----  Launching SIPp $sipps ----  "
                      sshpass -p "root12" ssh -tt -o StrictHostKeyChecking=no root@$ipList <<EOF1
                      pkill -f sipp
      
                      screen -S sipp -d -m bash -c 'cd /usr/local/src/sipp-3.3; ulimit -Hn 65535; ulimit -Sn 65535; ./sipp -i $ipList -mi $ipList -sf HA_demo.xml -inf HA_demo.csv 10.171.0.231:5060 -p 5060 -r 1 -rp 1s -l 1 -m 1 -watchdog_minor_threshold 1500 -watchdog_major_threshold 4000 -watchdog_major_maxtriggers 30 -trace_err -aa -d 350s -oocsn ooc_default -t u1 -trace_screen -skip_rlimit && exec bash'
                      exit
      EOF1
              done
              read -p 'Do you want to perform failover..(y/n)' cc
              if [[ $cc == "y" || $cc == "y" ]]; then
                      exit
              fi
      done
      

      感谢您的帮助!

      【讨论】:

      • while 条件中的一长串命令看起来更加复杂。最终的echo 将始终成功,因此这与在while true 循环中运行命令基本相同。
      • 您能详细说明一下吗?我怎样才能让它变短?实际上,代码所做的是它从作为呼叫生成器的文本文件中读取 SIPp 的 IP,并从用户输入的开始到结束循环遍历这些 IP。此外,它使用 sshpass 访问 VM 并创建一个屏幕,以便 SIPp 进程继续运行。 screen 在这里的目的是保持进程运行,使其不会退出。这只是我的 bash 脚本的一部分,因此需要退出,以便它可以移动到脚本的下一部分。
      • while unrelated command; other command; some more commands; this command; true do 之类的内容与while true; do unrelated command; other command; some more commanbds; this command; ... 基本相同
      • exit 退出整个脚本;同样,如果您想终止循环,执行此操作的命令是 break
      • 当然我会试一试。谢谢!
      猜你喜欢
      • 2018-02-22
      • 2017-04-26
      • 2018-08-19
      • 1970-01-01
      • 1970-01-01
      • 2022-12-04
      • 2013-09-24
      相关资源
      最近更新 更多