bash 计算包含错误文本的响应的脚本 - 命令未执行

bash script to count responses containing error text - command not executed

我需要请求一个页面 n 次并计算返回的错误页面数

ITERATIONS=100000
COUNTER=0; 
COUNT_ERROR=0; 
COUNT_EXPECTED=0; 
while (( $COUNTER < $ITERATIONS )); do 
COUNTER=$((COUNTER + 1)); 
curl http://www.example.com/example/path | grep -cim1 error; 
if (( $? == 0 )); then 
COUNT_ERROR=$((COUNT_ERROR + 1)) 
else 
COUNT_EXPECTED=$((COUNT_EXPECTED + 1))
fi; 
sleep 0.1; 
done; 
echo COUNT_ERROR=$COUNT_ERROR COUNT_EXPECTED=$COUNT_EXPECTED

此脚本正在返回

COUNT_ERROR=0 COUNT_EXPECTED=0

...所以 if 子句没有按预期执行

这里是修订版(基于 triplee 的评论):

iterations=100000; count_error=0; count_expected=0; for ((counter = 0; counter < iterations; ++counter)); do if curl http://www.example.com/example/path | grep -iq error; then count_error=$((count_error + 1)) else count_expected=$((count_expected + 1)); fi; sleep 0.1; done; echo count_error=$count_error count_expected=$count_expected

但是输出仍然是

count_error=0 count_expected=0

注意:测试机器包括 Windows 7 w/CygWin 和 MBP OSX Yosemite

这是完整的输出:

bash-3.1$ iterations=10; count_error=0; count_expected=0; for ((counter = 0; counter < iterations; ++counter)); do if curl http://www.example.com/example/path
| grep -iq jetty; then count_error=$((count_error + 1)) else count_expected=$((count_expected + 1)); fi; sleep 0.1; done; echo count_error=$count_error count_e
xpected=$count_expected
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  114k  100  114k    0     0   431k      0 --:--:-- --:--:-- --:--:--  431k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  114k  100  114k    0     0   666k      0 --:--:-- --:--:-- --:--:--  666k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  114k  100  114k    0     0   735k      0 --:--:-- --:--:-- --:--:--  735k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  114k  100  114k    0     0   490k      0 --:--:-- --:--:-- --:--:--  490k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  114k  100  114k    0     0   408k      0 --:--:-- --:--:-- --:--:--  408k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  114k  100  114k    0     0   735k      0 --:--:-- --:--:-- --:--:--  735k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  114k  100  114k    0     0   735k      0 --:--:-- --:--:-- --:--:--  735k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  114k  100  114k    0     0   565k      0 --:--:-- --:--:-- --:--:--  565k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  114k  100  114k    0     0   432k      0 --:--:-- --:--:-- --:--:--  432k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  114k  100  114k    0     0   925k      0 --:--:-- --:--:-- --:--:--  925k
count_error=0 count_expected=0
bash-3.1$

您在 if 后使用双圆括号的语法很奇怪。无论如何,检查是否成功的正确惯用方法是

if curl http://www.example.com/example/path | grep -iq error; then 

检查 curl 的成功或失败会更稳健,但如果网站总是 returns 一个 200 结果代码,你就不能这样做(也许改变网站以便出现问题时如实报告4xx或5xx HTTP错误代码?)

作为文体评论,您应该为自己的变量使用小写字母,并且 counter 循环会比 for 循环更优雅。

iterations=10000
for ((counter = 0; counter < iterations; ++counter)); do

行尾的分号是多余的;您需要在语句之间使用语句分隔符,但换行符也是有效的语句分隔符。

要获得一些解决方案:

OP 的问题是,尽管问题中包含多行代码,但代码仍作为 行执行。

多个命令甚至单个控制流语句的组件称为复合命令 [=121] =];例如,if,当 放在 单行 行时 必须 由 [= 分隔15=] 个实例,而换行符会自动分隔语句。

bash 中的 if 复合命令在其 if/else 形式中包含这些部分:

if [[ ... ]]; then ...;  else ...; fi  # Note the `;` chars. separating the components.

man bash 中搜索 Compound Commands 以获取完整故事。


在 OP 的情况下,;else 之前丢失,导致 else 分支被解释为 if 的(损坏的)部分支部指挥;例如:

$ if true; then echo TRUE else echo FALSE; fi  # note missing ';' before `else`
TRUE else echo FALSE

在这里,缺少的 ; 导致整个 else 分支被解释为 echo 的附加参数。

在其他情况下,两个分支都可能执行,因为语法错误:

$ if true; then i='TRUE'  else i='FALSE'; fi
-bash: else: command not found

此处,整个命令中断,$i 从未分配。
这就是 OP 案例中发生的事情(尽管我不清楚为什么他的输出不包含语法错误消息)。


建议:

  • 在一行中放置多个命令很快就会变得笨拙;考虑使用多行,最好是在脚本文件中。
  • 使用set -x调试您的命令以查看是否所有部分都在执行。
  • 当 post 在问题中输入代码时,post 它完全以重现问题所需的形式出现。如果这种形式对于人眼来说太难解析,post 具有更好格式的 附加 版本(并明确它仅用于显示)。
  • 一定要弄清楚你的代码是运行命令行还是来自脚本

对 bash 代码有很好的文体建议;有一个值得添加:

  • 在 bash 中,您可以使用算术计算递增变量 C 风格:

    (( ++count_error )) # alternative to count_error=$(( count_error + 1 ))
    

三重状态:

I'm not familiar with CygWin but I would be vaguely surprised if it did the right thing without a shebang -- it's probably running Bash in POSIX mode, which means many of the Bashisms will be syntax errors, or just not behave like you want.

事实上(无论 bash 运行s 在 CygWin (Windows) 还是在 Unix 上:

  • 语法方面,当bash时,除了进程替换(<(...))之外的所有bash主义仍然可用POSIX mode 中的 运行 秒;但是,行为 有许多细微的变化,因此最好明确控制给定脚本 运行 所处的模式。

  • 当 bash 运行 是一个没有 shebang 行的可执行 shell 脚本时,它 运行 就像脚本有一个bash shebang 行;换句话说:它在 POSIX 模式下 而不是 运行。