这个bash脚本如何导致无限循环?

时间:2013-02-20 22:28:28

标签: perl bash tee ifs

从一些谷歌搜索(我不是任何bash专家)我能够组合一个bash脚本,允许我运行测试套件并在运行时在底部输出状态栏。它通常需要大约10个小时,状态栏告诉我通过了多少次测试以及失败了多少次。

它有时很好用,但偶尔我会遇到一个无限循环,这很糟糕(mmm-kay?)。这是我正在使用的代码:

#!/bin/bash
WHITE="\033[0m"
GREEN="\033[32m"
RED="\033[31m"

(run_test_suite 2>&1) | tee out.txt |
while IFS=read -r line;
do
    printf "%$(tput cols)s\r" " ";
    printf "%s\n" "$line";

    printf "${WHITE}Passing Tests: ${GREEN}$(grep -c passed out.txt)\t"         2>&1;
    printf "${WHITE}Failed Tests: ${RED}$(   grep -c FAILED out.txt)${WHITE}\r" 2>&1;
done

当我遇到这个错误时会发生什么?我会有一个无限重复的错误消息,导致日志文件(out.txt)成为一个多兆字节的怪物(我认为它进入了GB的一次)。这是一个重复的示例错误(每组之间有四行空格):

warning caused by MY::Custom::Perl::Module::TEST_FUNCTION
print() on closed filehandle GEN3663 at /some/CPAN/Perl/Module.pm line 123.

我已尝试取消2>&1重定向,我尝试将while IFS=read -r line;更改为while read -r line;,但我一直在获得无限循环。更奇怪的是这似乎发生在大多数时间,但有时候我完成了长测试套件没有任何问题。

修改

我写这篇文章的原因是从黑色和黑色升级白色测试套件到颜色编码的测试套件(因此ANSI代码)。以前,我会使用

运行测试套件
run_test_suite > out.txt 2>&1 &
watch 'grep -c FAILED out.txt; grep -c passed out.txt; tail -20 out.txt'

以这种方式运行它会从Perl获得相同的警告,但会将其打印到文件并继续前进,而不是卡在无限循环中。使用watch,还可以打印[32m之类的内容,而不是将文本实际呈现为绿色。

2 个答案:

答案 0 :(得分:0)

该错误出现在您的脚本中。这不是IO错误;这是一个非法的参数错误。当您作为句柄提供的变量根本不是句柄,或者是您已关闭的变量时,会发生该错误。

写入损坏的管道导致该进程被SIGPIPEprint中的$!设置为EPIPE时返回false。

答案 1 :(得分:0)

我能够修复perl错误,并且经过一些修改后,bash脚本似乎现在运行良好。但是,似乎这将是运行测试套件的更安全的方式,以防将来发生类似的情况:

#!/bin/bash
WHITE="\033[0m"
GREEN="\033[32m"
RED="\033[31m"

run_full_test > out.txt 2>&1 &
tail -f out.txt | while IFS= read line; do
    printf "%$(tput cols)s\r" " ";
    printf "%s\n" "$line";

    printf "${WHITE}Passing Tests: ${GREEN}$(grep -c passed     out.txt)\t"         2>&1;
    printf "${WHITE}Failed Tests: ${RED}$(   grep -c 'FAILED!!' out.txt)${WHITE}\r" 2>&1;
done

这有一些缺点。主要是,如果我点击Ctrl-C停止测试,它似乎已停止,但真的run_full_test仍然在后台运行,我需要记住手动杀死它。此外,测试完成后tail -f仍在运行。换句话说,这里运行了两个进程并且它们不同步。

这是原始脚本,略有修改,解决了这些问题,但并非万无一失(即如果run_full_test出现问题,可能会陷入无限循环):

#!/bin/bash
WHITE="\033[0m"
GREEN="\033[32m"
RED="\033[31m"

(run_full_test 2>&1) | tee out.txt | while IFS= read line; do
    printf "%$(tput cols)s\r" " ";
    printf "%s\n" "$line";

    printf "${WHITE}Passing Tests: ${GREEN}$(grep -c passed     out.txt)\t"         2>&1;
    printf "${WHITE}Failed Tests: ${RED}$(   grep -c 'FAILED!!' out.txt)${WHITE}\r" 2>&1;
done