Bash while 循环的脚本意外结果

Bash script unexpected result for while loop

我有以下 bash 脚本来停止 Apache 服务器。我没有收到错误,而是收到意外结果。

#!/bin/bash

/etc/init.d/httpd stop
if [[ $? -ne 0 ]]
then
    exit 1
fi
RTN=10
while [[ $RTN -gt 0 ]]
echo "Before" $RTN
do
    sleep 5
    RTN=`ps -C httpd | wc -l`
    RTN=$(( RTN - 1 ))
echo "After" $RTN
done 

exit 0

我得到了以下答案,这是我不希望的,而且是无限打印的:

Before 10
After 0

Before 0
After 0

Before 0
After 0

我希望打印:

Before 10
After -1 
#and exit here

谁能告诉我发生了什么事?

这并不像您认为的那样有效:

while [[ $RTN -gt 0 ]]
echo "Before" $RTN
do

您希望 echo do 之后出现。在 do 之前,它是 list-1 条件的一部分,而不是 list-2 主体。并且,根据 bash 文档(我的粗体):

The while command continuously executes the list list-2 as long as the last command in the list list-1 returns an exit status of zero.

您可以看到以下脚本之间的区别,与您的类似:

#!/usr/bin/bash
RTN=2
while [[ $RTN -gt 0 ]]
echo "Before" $RTN
do
    sleep 1
    RTN=$(( RTN - 1 ))
echo "After" $RTN
done

哪个输出(无穷大):

Before 2
After 1
Before 1
After 0
Before 0
After -1
Before -1
After -2
Before -2

当您将 echo 移动到 内部 主体时:

#!/usr/bin/bash
RTN=2
while [[ $RTN -gt 0 ]]
do
    echo "Before" $RTN
    sleep 1
    RTN=$(( RTN - 1 ))
    echo "After" $RTN
done

然后正确终止:

Before 2
After 1
Before 1
After 0
<returns to prompt>

一旦做出更改,循环就会正确终止,因为您的 ps 命令正在生成这些值。


此外,如果您想找出进程列表中的内容(并且可能导致结果为零而不是负数),请在检查计数之前输出进程列表:

:
ps -C httpd                 # Add this line temporarily.
RTN=`ps -C httpd | wc -l`
:

你的ps -C httpd命令总是returns一行:PID TTY TIME CMD(基本上是ps输出的标题)被wc -l计为1当没有进程时 运行。如果 httpd 是 运行,则行数将大于 1。

因此$((RTN -1))变成了0

编辑:

我注意到,您的 while 循环有一个错误:

while [[ $RTN -gt 0 ]]
echo "Before" $RTN
do

改为:

while [[ $RTN -gt 0 ]]
do
echo "Before" $RTN