I am modifying a shell script, which uses Makefile to test code in different test benches, currently the shell script only echo SUCCESS and FAILURE, i want to modify this shell script to search through the output trace strings which are being written into another file at the same location where the Makefile is called upon namely trace.log. If it finds the word "ERROR"(which is a trace string) i want the test to say FAILURE
!/usr/bin/env bash
#set -e
BASEDIR=$(pwd)
REPOROOT=`git rev-parse --show-toplevel`
RED="`tput setaf 1`"
GREEN="`tput setaf 2`"
BLUE="`tput setaf 4`"
NORM="`tput sgr0`"
Test() {
pushd ${REPOROOT}/rr/Fmda/body > /dev/null
tests=`find . -type f | grep "test.xml" | sed "s/test\.xml//"`
for t in $tests; do
testname=`echo $t | sed "s/\.\///" | sed "s/\/test\///"`
echo -e "${BLUE}EXECUTING $testname TEST${NORM}"
pushd $t > /dev/null
make test_svp
if [ $? -eq 0 ]; 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
}
I have no background in shell scripting. I understood what's written here by googling the constructs, but still I didn't understand how for t in $tests
works and what sed
does.
From what i thought would work for my problem is
error=trace.log|grep "ERROR"
if [ $? -eq 0] && [ !error ]; then
After studying a bit about $?
and shell scripting I know this wont work, what should I have to do to achieve this thing?
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)?
log=file.log
if grep ERRORS "$log" ; then echo BIG FAILURE ; fi
Should work with any shell.
(Thanks to tripleee useful comments)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.