简体   繁体   English

如何在Shell脚本中从测试的输出中搜索“ ERROR”字符串?

[英]How to search for “ERROR” string from the output of the test in shell scripting?

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. 我正在修改一个shell脚本,该脚本使用Makefile在不同的测试台上测试代码,当前该shell脚本仅回显SUCCESS和FAILURE,我想修改此shell脚本以搜索正在写入到另一个文件的输出跟踪字符串。在同一位置调用Makefile,即trace.log。 If it finds the word "ERROR"(which is a trace string) i want the test to say FAILURE 如果它找到单词“ ERROR”(这是一个跟踪字符串),我希望测试说失败

!/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. 我没有shell脚本方面的背景。 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. 我通过搜索构造了解了这里写的内容,但我仍然不了解for t in $tests工作方式以及sed作用。

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? 和Shell脚本编写,我知道这行不通,我应该怎么做才能实现这一目标?

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 . for variable in one two threefor循环for variable in one two three将在循环的主体中运行,将$variable设置为在第一次迭代中设置为one ,在第二次迭代中设置为two ,然后设置为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. sed本身就是一种脚本语言,尽管通常它仅用于琐碎的字符串替换。 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. sed脚本s/regex/replacement/g将用其处理文件中的静态字符串replacement正则表达式上的所有匹配项。 (In the absence of the /g flag, only the first occurrence on each input line will be replaced.) (在没有/g标志的情况下,将仅替换每个输入行上的第一个匹配项。)

Generally, scripts should examine the exit status from a command, not grep for human-readable strings. 通常,脚本应该检查命令的退出状态,而不是人类可读字符串的grep。 The make command already illustrates this, though it is not entirely idiomatic. make命令已经说明了这一点,尽管它并不完全是惯用的。

Incidentally, the shebang on the first line must start with exactly the two characters #! 顺便说一句,第一行的shebang必须以两个字符#!开头#!

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 . 请注意在make之后添加了grep The && says "and" and the ! &&说“和”,然后说! inverts the exit code from grep (so this is true if grep fails to find any matches). 反转grep的退出代码(因此,如果grep找不到任何匹配项,则为true)。 The -q suppresses the output of matches by grep and causes it to stop searching as soon as it finds the first match. -q抑制grep输出的匹配项,并使其在找到第一个匹配项后立即停止搜索。

More tangentially, I would regard pushd and popd as intended for interactive use. 更切地讲,我认为pushdpopd用于交互用途。 Shell scripts usually just cd in a subshell and then when the subshell finishes, you are back in the directory where you started. Shell脚本通常只是在子Shell中使用cd ,然后在子Shell完成后,您便回到了开始的目录中。 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 ). ... -quit谓词在很大程度上是GNU find扩展(stol ...从这里受宠若惊)。

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)? test.xml是测试的实际文件名,还是只是后缀(甚至是中间的某处)?

log=file.log
if grep ERRORS "$log" ; then echo BIG FAILURE ; fi

Should work with any shell. 应该与任何外壳一起工作。

(Thanks to tripleee useful comments) (感谢三人有用的评论)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM