我可以缩短这个bash脚本吗?

时间:2015-03-15 08:09:15

标签: bash

我们为Chrome,Firefox和Safari创建了扩展程序,我们希望使用Selenium测试扩展程序。我创建了大约15个Selenium测试,我们希望每8小时使用crontab运行它们(我们可能希望更改为4小时后)。我希望通过电子邮件收到每个测试的结果,并且我们还希望在上午8:15的测试结束后每天收到每日报告。这是我的脚本(我只展示前两个测试):

run_daily_selenium_tests.sh

#!/bin/bash

today_date_hour=`TZ='Asia/Jerusalem' date +"%Y-%m-%d_%H"`
start_hour=`TZ='Asia/Jerusalem' date +"%H"`

cd /home/ubuntu/selenium_tests
python /home/ubuntu/selenium_tests/tests/chrome_inbox_without_extension_test.py >/home/ubuntu/logs/selenium_tests/"$today_date_hour"_chrome_inbox_without_extension_test.log 2>&1
cat /home/ubuntu/logs/selenium_tests/"$today_date_hour"_chrome_inbox_without_extension_test.log | mail -s "Chrome Inbox Without Extension Test - `TZ='Asia/Jerusalem' date +"%Y-%m-%d %H:%M:%S"`" <my_email_address>
python /home/ubuntu/selenium_tests/tests/chrome_inbox_1_with_extension_test.py >/home/ubuntu/logs/selenium_tests/"$today_date_hour"_chrome_inbox_1_with_extension_test.log 2>&1
cat /home/ubuntu/logs/selenium_tests/"$today_date_hour"_chrome_inbox_1_with_extension_test.log | mail -s "Chrome Inbox 1 With Extension Test - `TZ='Asia/Jerusalem' date +"%Y-%m-%d %H:%M:%S"`" <my_email_address>

if [ $start_hour = "08" ]; then
    cd /home/ubuntu
    /home/ubuntu/scripts/send_daily_report.sh
fi

print_daily_report.sh

#!/bin/bash

today=`TZ='Asia/Jerusalem' date +"%Y-%m-%d"`
yesterday=`TZ='Asia/Jerusalem' date +"%Y-%m-%d" -d "yesterday"`

cd /home/ubuntu
echo "Chrome Inbox Without Extension Test - $today: `ls -1 /home/ubuntu/logs/selenium_tests/\"$yesterday\"_1*_chrome_inbox_without_extension_test.log /home/ubuntu/logs/selenium_tests/\"$yesterday\"_2*_chrome_inbox_without_extension_test.log /home/ubuntu/logs/selenium_tests/\"$today\"_0*_chrome_inbox_without_extension_test.log | wc -l` tests total, `fgrep -l -v FAILED /home/ubuntu/logs/selenium_tests/\"$yesterday\"_1*_chrome_inbox_without_extension_test.log /home/ubuntu/logs/selenium_tests/\"$yesterday\"_2*_chrome_inbox_without_extension_test.log /home/ubuntu/logs/selenium_tests/\"$today\"_0*_chrome_inbox_without_extension_test.log | wc -l` passed, `fgrep -l FAILED /home/ubuntu/logs/selenium_tests/\"$yesterday\"_1*_chrome_inbox_without_extension_test.log /home/ubuntu/logs/selenium_tests/\"$yesterday\"_2*_chrome_inbox_without_extension_test.log /home/ubuntu/logs/selenium_tests/\"$today\"_0*_chrome_inbox_without_extension_test.log | wc -l` failed."
echo "Chrome Inbox 1 With Extension Test - $today: `ls -1 /home/ubuntu/logs/selenium_tests/\"$yesterday\"_1*_chrome_inbox_1_with_extension_test.log /home/ubuntu/logs/selenium_tests/\"$yesterday\"_2*_chrome_inbox_1_with_extension_test.log /home/ubuntu/logs/selenium_tests/\"$today\"_0*_chrome_inbox_1_with_extension_test.log | wc -l` tests total, `fgrep -l -v FAILED /home/ubuntu/logs/selenium_tests/\"$yesterday\"_1*_chrome_inbox_1_with_extension_test.log /home/ubuntu/logs/selenium_tests/\"$yesterday\"_2*_chrome_inbox_1_with_extension_test.log /home/ubuntu/logs/selenium_tests/\"$today\"_0*_chrome_inbox_1_with_extension_test.log | wc -l` passed, `fgrep -l FAILED /home/ubuntu/logs/selenium_tests/\"$yesterday\"_1*_chrome_inbox_1_with_extension_test.log /home/ubuntu/logs/selenium_tests/\"$yesterday\"_2*_chrome_inbox_1_with_extension_test.log /home/ubuntu/logs/selenium_tests/\"$today\"_0*_chrome_inbox_1_with_extension_test.log | wc -l` failed."

send_daily_report.sh

#!/bin/bash

today=`TZ='Asia/Jerusalem' date +"%Y-%m-%d"`

cd /home/ubuntu
/home/ubuntu/scripts/print_daily_report.sh 2>&1 | mail -s "Selenium Tests Daily Report - $today" <my_email_address>

上面的脚本有两个问题:

  1. 如果日志文件不存在,我收到错误消息“没有这样的文件或目录”,我想将错误重定向到dev / null。
  2. print_daily_report.sh 中的行太长,是否可以缩短它们?每行包含9个带通配符的文件,它们是重复3次的相同文件。
  3. 顺便说一句,我不想​​更改 send_daily_report.sh 将错误重定向到dev / null,而只更改 print_daily_report.sh

    更新:如果我在 print_daily_report.sh 2>/dev/null之前添加wc -l,我就不会收到错误消息,但对于某些测试(我们今天只进行过一次测试),我收到“总共1次测试,1次测试,1次失败”。我检查了测试失败,但我想计算不包含单词“FAILED”的文件数量,我该怎么做? (我的命令fgrep -l -v FAILED不正确)

    解决方案:我找到了一个基于以下两个答案的解决方案。这是我的解决方案(我只更改了前两个脚本):

    run_daily_selenium_tests.sh

    #!/bin/bash
    
    cd /home/ubuntu/selenium_tests
    
    today_date_hour=`TZ='Asia/Jerusalem' date +"%Y-%m-%d_%H"`
    start_hour=`TZ='Asia/Jerusalem' date +"%H"`
    selenium_test_prefix="/home/ubuntu/selenium_tests/tests/"
    selenium_test_suffix=".py"
    log_prefix="/home/ubuntu/logs/selenium_tests/"
    
    run_selenium_test()
    {
        selenium_test_file_name="${selenium_test_prefix}${file_name}${selenium_test_suffix}"
        log_suffix="_${file_name}.log"
        log_file_name="${log_prefix}${today_date_hour}${log_suffix}"
        python "$selenium_test_file_name" >"$log_file_name" 2>&1
        cat "$log_file_name" | mail -s "$test_name - `TZ='Asia/Jerusalem' date +"%Y-%m-%d %H:%M:%S"`" <my_email_address>
    }
    
    file_name="chrome_inbox_without_extension_test"
    test_name="Chrome Inbox Without Extension Test"
    run_selenium_test
    
    file_name="chrome_inbox_1_with_extension_test"
    test_name="Chrome Inbox 1 With Extension Test"
    run_selenium_test
    
    if [ $start_hour = "08" ]; then
        cd /home/ubuntu
        /home/ubuntu/scripts/send_daily_report.sh
    fi
    

    print_daily_report.sh

    #!/bin/bash
    
    cd /home/ubuntu
    
    today=`TZ='Asia/Jerusalem' date +"%Y-%m-%d"`
    yesterday=`TZ='Asia/Jerusalem' date +"%Y-%m-%d" -d "yesterday"`
    log_prefix="/home/ubuntu/logs/selenium_tests/"
    
    print_test_results()
    {
        log_suffix="_${file_name}.log"
        yesterday_logs="${log_prefix}${yesterday}_[1,2]*${log_suffix}"
        today_logs="${log_prefix}${today}_0*${log_suffix}"
        echo -n "$test_name - $today: `ls -1 $yesterday_logs $today_logs 2>/dev/null | wc -l 2>/dev/null` tests total, "
        echo -n "`fgrep -L FAILED $yesterday_logs $today_logs 2>/dev/null | wc -l 2>/dev/null` passed, "
        echo "`fgrep -l FAILED $yesterday_logs $today_logs 2>/dev/null | wc -l 2>/dev/null` failed."
    }
    
    file_name="chrome_inbox_without_extension_test"
    test_name="Chrome Inbox Without Extension Test"
    print_test_results
    
    file_name="chrome_inbox_1_with_extension_test"
    test_name="Chrome Inbox 1 With Extension Test"
    print_test_results
    

2 个答案:

答案 0 :(得分:1)

在可读性和可维护性方面,有两个简单的步骤来改进脚本:

  1. 不要使用反引号,而是使用$(expansion)这种形式  更容易阅读和嵌套到其他表达式。
  2. 使用函数构建代码,以便进行调试  单独的功能和复杂的名称  操作。
  3. 不是每个人都同意这一点,但我也建议初学者一直这样做 偏好printf优于echo,它更强大,更易于使用。

    这将是您的脚本的第一次重写 - 直到第一次报告:

    #!/bin/bash
    
    today=$(TZ='Asia/Jerusalem' date +"%Y-%m-%d")
    yesterday=$(TZ='Asia/Jerusalem' date +"%Y-%m-%d" -d "yesterday")
    
    test_report()
    {
        local total passed failed
    
        total=$(ls -1 "$@" | wc)
        passed=$(fgrep -L FAILED "$@" | wc)
        failed=$(fgrep -l FAILED "$@" | wc)
    
        printf 'Chrome Inbox Without Extension Test - %s: ' "${today}"
        printf '%s tests total, %s passed, %s failed.\n'\
               "${total}" "${passed}" "${failed}"
    }
    
    test_report\
        /home/ubuntu/logs/selenium_tests/"${yesterday}"_1*_chrome_inbox_without_extension_test.log\
        /home/ubuntu/logs/selenium_tests/"{$yesterday}"_2*_chrome_inbox_without_extension_test.log\
        /home/ubuntu/logs/selenium_tests/"${today}"_0*_chrome_inbox_without_extension_test.log
    

    这严格遵循原始脚本,并且还有一个缺点,即如果不存在测试,它将产生垃圾。

    有一种更特殊的方法可以解决您的问题:首先计算有关我们测试结果的原始数据,然后对其进行聚合。在我们的特定情况下,这意味着编写一个函数test_analyse,它准备一个包含两行的表,一个测试的名称,以及一个失败或传递的标记。然后我们可以聚合这个表来产生最终报告。最后一步通常用 Awk 完成 - 这基本上是 Awk 的用途 - 但你基本上可以在这里使用你最喜欢的脚本语言,甚至是shell。

    #!/bin/bash
    
    TODAY=$(TZ='Asia/Jerusalem' date +"%Y-%m-%d")
    YESTERDAY=$(TZ='Asia/Jerusalem' date +"%Y-%m-%d" -d "yesterday")
    
    test_analyse()
    {
        local today yesterday extension testdir
        local testlog testresult
    
        testdir=""
    
        yesterday="$1"
        toady="$2"
    
        if [ "$3" = 'yes' ]; then
            extension='with_extension'
        else
            extension='without_extension'
        fi
    
        find /home/ubuntu/logs/selenium_tests\
             -name "${yesterday}_1*_chrome_inbox_${extension}_test.log"\
             -o -name "${yesterday}_2*_chrome_inbox_${extension}_test.log"\
             -o -name "${today}_0*_chrome_inbox_${extension}_test.log" \
            | while read testlog; do
                  if grep -q 'FAILED' "${testlog}"; then
                      testresult='FAILED'
                  else
                      testresult='PASSED'
                  fi
                  printf '%s|%s\n' "${testlog}" "${testresult}"
              done
    }
    
    test_report()
    {
        test_analyse "$@" | awk -F '|' -v today="$2" -v extension="$3" '
    {t+=1}
    $2 ~ /FAILED/ {f+=1}
    $2 ~ /PASSED/ {p+=1}
    END {
     if(extension == "yes") {
       complement = "With Extension"
     } else {
       complement = "Without Extension"
     }
     print "Chrome Inbox " complement " Test = " today ": "\
       t " tests total, " p " passed, " f " failed."
    '
    }
    
    test_report "${YESTERDAY}" "${TODAY}" 'no'
    test_report "${YESTERDAY}" "${TODAY}" 'yes'
    

答案 1 :(得分:1)

要缩短print_daily_report.sh中的行,您可以创建重复信息的一些变量。例如,您可以拥有以下变量:

suffix="/home/ubuntu/logs/selenium_tests/"
prefix="chrome_inbox_without_extension_test.log"
yesterdayLogs="${prefix}\"$yesterday\"_[1,2]*_${suffix}"
todayLogs="${prefix}\"$today\"_0*_${suffix}"

这可能会使您的第一个回声线看起来像这样:

echo "Chrome Inbox Without Extension Test - $today: `ls -1 $yesterdayLogs $todayLogs | wc -l` tests total, `fgrep -L FAILED $yesterdayLogs $todayLogs | wc -l` passed, `fgrep -l FAILED $yesterdayLogs $todayLogs | wc -l` failed."

你也可以将这个回声分成多行,仍然得到相同的输出:

echo -n "Chrome Inbox Without Extension Test - $today: `ls -1 $yesterdayLogs $todayLogs | wc -l` tests total,"
echo -n "`fgrep -L FAILED $yesterdayLogs $todayLogs | wc -l` passed,"
echo "`fgrep -l FAILED $yesterdayLogs $todayLogs | wc -l` failed."

echo的-n选项意味着它不会在结尾处打印换行符。你应该能够应用同样的技术来缩短你的第二个回声,但我想我会让你玩这个来磨练你的Bash技能。

对于错误抑制,我建议在调用脚本时重定向stderr。所以你的行将成为

/home/ubuntu/scripts/print_daily_report.sh 2>/dev/null | mail -s "Selenium Tests Daily Report - $today" <my_email_address>

这将为您提供相同的结果,但没有任何错误输出。我知道你不想改变send_daily_report.sh文件,但这将是你想要的最简单的方法,而且实际上也没有理由(据我所见)。如果不这样做,则必须将重定向行添加到所有命令中,因此您的echo语句将变为:

echo -n "Chrome Inbox Without Extension Test - $today: `ls -1 $yesterdayLogs $todayLogs 2>/dev/null | wc -l 2>/dev/null` tests total,"
echo -n "`fgrep -L FAILED $yesterdayLogs $todayLogs 2>/dev/null | wc -l 2>/dev/null` passed,"
echo "`fgrep -l FAILED $yesterdayLogs $todayLogs 2>/dev/null | wc -l 2>/dev/null` failed."