質問

From some Googling (I'm no bash expert by any means) I was able to put together a bash script that allows me to run a test suite and output a status bar at the bottom while it runs. It typically takes about 10 hours, and the status bar tells me how many tests passed and how many failed.

It works great sometimes, however occasionally I will run into an infinite loop, which is bad (mmm-kay?). Here's the code I'm using:

#!/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

What happens when I encounter the bug is I'll have an error message repeat infinitely, causing the log file (out.txt) to become some multi-megabyte monstrosity (I think it got into the GB's once). Here's an example error that repeats (with four lines of whitespace between each set):

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

I've tried taking out the 2>&1 redirect, and I've tried changing while IFS=read -r line; to while read -r line;, but I keep getting the infinite loop. What's stranger is this seems to happen most of the time, but there have been times I finish the long test suite without any problems.

EDIT:

The reason I'm writing this is to upgrade from a black & white test suite to a color-coded test suite (hence the ANSI codes). Previously, I would run the test suite using

run_test_suite > out.txt 2>&1 &
watch 'grep -c FAILED out.txt; grep -c passed out.txt; tail -20 out.txt'

Running it this way gets the same warning from Perl, but prints it to the file and moves on, rather than getting stuck in an infinite loop. Using watch, also prints stuff like [32m rather than actually rendering the text as green.

役に立ちましたか?

解決

I was able to fix the perl errors and the bash script seems to work well now after a few modifications. However, it seems this would be a safer way to run the test suite in case something like that were to happen in the future:

#!/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

There are some downsides to this. Mainly, if I hit Ctrl-C to stop the test, it appears to have stopped, but really run_full_test is still running in the background and I need to remember to kill it manually. Also, when the test is finished tail -f is still running. In other words there are two processes running here and they are not in sync.

Here is the original script, slightly modified, which addresses those problems, but isn't foolproof (i.e. can get stuck in an infinite loop if run_full_test has issues):

#!/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

他のヒント

The bug is in your script. That's not an IO error; that's an illegal argument error. That error happens when the variable you provide as a handle isn't a handle at all, or is one that you've closed.

Writing to a broken pipe results in the process being killed by SIGPIPE or in print returning false with $! set to EPIPE.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top