如何编写一个可以一般测试执行命令输出的Bash函数?

时间:2017-03-01 09:32:03

标签: bash shell testing

我想写一个小的Bash函数,我可以将命令作为字符串和搜索针传递,如果命令的执行输出包含给定的搜索针,它应该打印一些“OKAY”,否则“ERROR”。

这就是我到目前为止所提出的:

red=`tput setaf 1`
green=`tput setaf 2`
reset=`tput sgr0`

function psa_test {
  result=$($1 2>&1)
  echo "Result: $result"
  if [[ $result == *"$2"* ]]; then
    echo "[${green} OK  ${reset}] $3"
  else
    echo "[${red}ERROR${reset}] $3"
  fi
  echo "        Command: '$1' | Needle: '$2' | Name: '$3'"  
}

如果我像那样调用它

psa_test 'curl -v google.com' "HTTP 1.1" "Testing google.com"

效果很好:

# .. output
[ OK  ] Testing google.com
            Command: 'curl -v google.com' | Needle: 'HTTP 1.1' | Name: 'Testing google.com'

但是如果我的命令中有一些嵌入的字符串,它就不再起作用了,例如:

psa_test 'curl --noproxy "*" http://www1.in.example.com' "HALLO 1" "HTTP www1.in.example.com"

输出:

# Proxy answers with HTML error document ... <html></html> ... saying
# that it can't resolve the domain (which is correct as 
# it is an internal domain). But anyway, the --noproxy "*" option 
# should omit all proxies!
[ERROR] HTTP www1.in.example.com
        Command: 'curl --noproxy "*" http://www1.in.example.com' | Needle: 'HALLO 1' | Name: 'HTTP www1.in.example.com'

请注意,如果我执行

curl --noproxy "*" http://www1.in.example.com
我的shell中的

会忽略代理(我们想要的),而

curl --noproxy * http://www1.in.example.com

没有。

如果我尝试使用mysql -u ... -p ... -e "SELECT true"测试MySQL数据库,我会遇到类似的行为。所以我猜这与报价有关。如果有人能给我一些改进这个功能的提示,我会很高兴的。谢谢!

1 个答案:

答案 0 :(得分:2)

尝试将整个命令作为单个字符串提供需要以各种不方便的方式引用。我建议你尝试一种不需要的方法。

#!/bin/bash
red=`tput setaf 1`
green=`tput setaf 2`
reset=`tput sgr0`

psa_test()
{
  local needle="$1"
  local name="$2"
  local -a command=("${@:3}")
  local result ; result=$("${command[@]}" 2>&1)
  echo "Result: $result"
  if
    [[ $result == *$needle* ]]
  then
    echo "[$green OK  $reset] $name"
  else
    echo "[$red ERROR $reset] $name"
  fi
  echo "        Command: ${command[@]} | Needle: $needle | Name: $name"
}

然后你可以通过将你的命令作为一个不带引号的字符串来调用你的函数,就像你在交互式shell中调用它一样,但是先放入前两个参数。

psa_test "HTTP/1.1" "Testing google.com" curl -v google.com

一些注意事项:

  • 该命令存储在一个数组中,并通过扩展其所有元素来执行,单独引用以防止分词(这是"${command[@]}"所做的)。

  • 数组扩展的双引号非常重要,因为它们告诉shell将数组扩展为每个数组元素一个单词,并防止在每个数组元素内部发生单词拆分(以允许包含空格的数组元素) ,例如)。

  • 您应该在函数内声明变量local。它并不是绝对必要的,但是当你有多个具有相同名称的变量的函数时,它将使脚本更易于调试,并且不易出现令人讨厌的失败模式。

  • 我认为&#34; HTTP / 1.1&#34;是您想要的搜索字符串

  • 如果需要考虑性能,则应尝试使用不同的文本匹配方法(即Bash regex =~grep),以查看哪种方法最适合您的数据。

    < / LI>

请注意,上述脚本可以通过以下方式简化:

  • local -a command=("${@:3}")
  • 替换shift 2
  • 在{/ 1}}处使用"${command[@]}"替换

在这种情况下它会有意义,但我利用这个机会来说明构建命令如何作为数组工作,因为它在脚本中通常很有用,但在使用位置参数的简单情况下,它可以很好地工作并提高可读性。