The for
loop for variable in one two three
will run the body of the loop with $variable
set to one
on the first iteration, two
on the next, and then to three
. When the loop finishes, the variable retains the last value it had in the loop.
sed
is a scripting language in its own right, though typically it is only used for trivial string substitutions. The sed
script s/regex/replacement/g
will replace every match on the regular expression with the static string replacement
in the file(s) it processes. (In the absence of the /g
flag, only the first occurrence on each input line will be replaced.)
Generally, scripts should examine the exit status from a command, not grep for human-readable strings. The make
command already illustrates this, though it is not entirely idiomatic.
Incidentally, the shebang on the first line must start with exactly the two characters #!
Here is a refactoring with comments.
#!/usr/bin/env bash
#set -e
# Use lower case for your private variables
# BASEDIR was never used for anything
# Consistently use modern command substitution syntax
reporoot=$(git rev-parse --show-toplevel)
RED="$(tput setaf 1)"
GREEN="$(tput setaf 2)"
BLUE="$(tput setaf 4)"
NORM="$(tput sgr0)"
Test() {
# Maybe don't pushd; see below
# Quote the variable properly
pushd "$reporoot/rr/Fmda/body" > /dev/null
# Refactor to avoid useless use of grep
tests=$(find . -type f | sed -n "s/test\.xml//p")
for t in $tests; do
# Proper quoting; refactor to a single sed script
# Fix sed syntax error (too many slashes)
testname=$(echo "$t" | sed "s/\.\//;s%/test/%%")
echo -e "${BLUE}EXECUTING $testname TEST${NORM}"
pushd "$t" > /dev/null
# Use "if" like it was meant to
# Add grep condition
if make test_svp && ! grep -q "ERROR" trace.log; then
echo -e "${GREEN}SUCCESS IN $testname TEST MOVING ON!${NORM}"
else
echo "${RED}FAILURE IN $testname TEST${NORM}"
exit 1
fi
popd >/dev/null
done
popd >/dev/null
}
Notice the addition of the grep
after the make
. The &&
says "and" and the !
inverts the exit code from grep
(so this is true if grep
fails to find any matches). The -q
suppresses the output of matches by grep
and causes it to stop searching as soon as it finds the first match.
More tangentially, I would regard pushd
and popd
as intended for interactive use. Shell scripts usually just cd
in a subshell and then when the subshell finishes, you are back in the directory where you started. But here, a more fundamental refactoring might be called for.
For a somewhat more complex but hopefully robust refactoring, maybe do
Test() {
find "$reporoot/rr/Fmda/body" -name 'test.xml' \
\( -execdir sh -c '
# XXX TODO: maybe replace with parameter substitutions
testname=$(echo "$1" | sed "s%/test\.xml$%%;s/\.\//;s%/test/%%")
echo -e "${BLUE}EXECUTING $testname TEST${NORM}"
make test_svp &&
! grep -q "ERROR" trace.log &&
echo -e "${GREEN}SUCCESS IN $testname TEST MOVING ON!${NORM}" ||
{
echo "${RED}FAILURE IN $testname TEST${NORM}"
exit 1; }' _ {} \; -o -quit \)
}
... though the -quit
predicate is very much a GNU find
extension (stol... flattered from here).
This has some assumptions about your test file names which might not be correct. Is test.xml
the actual file name of the test, or just a suffix (or even somewhere in the middle)?