如何编写一个 Bash 函数来测试执行命令的输出? [英] How to write a Bash function that can generically test the output of executed commands?

查看:39
本文介绍了如何编写一个 Bash 函数来测试执行命令的输出?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to write a small Bash function that I can pass a command as string and a search needle and if the execution output of the command contains the given search needle, it should print some "OKAY", else "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'

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

But if I have some embedded string in my command, it doesn't work anymore, e.g.:

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 中确实忽略了代理(我们想要的),而

in my shell does ignore proxies (which we want), while

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

没有.

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

I got some similar behaviour if I try to test a MySQL database with mysql -u ... -p ... -e "SELECT true" . So I guess it has something to do with the quotes. Would be glad if someone can give me a hint to improve this function. Thanks!

推荐答案

试图以单个字符串的形式提供整个命令需要以各种不方便的方式引用.我建议您尝试一种稍微不同的方法,不需要这样做.

Trying to provide entire commands as a single string requires quoting in all kinds of inconvenient ways. I would suggest you try a slightly different approach that does not require that.

#!/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 中调用它一样,但将前两个参数放在前面.

Then you can call your function by passing your command as an unquoted string, exactly like you would call it in an interactive shell, but putting the first two arguments before.

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

一些注意事项:

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

数组展开周围的双引号非常重要,因为它们告诉shell每个数组元素将数组展开一个字,并防止每个数组元素内部发生分词(允许数组元素包含空格,例如).

The double quotes around the array expansion are very important, because they tell the shell to expand the array one word per array element, and prevent word splitting from occurring inside each array element (to allow for array elements containing spaces, for instance).

你应该在函数内部声明你的局部变量.这不是绝对必要的,但是当您有多个具有同名变量的函数时,它会使脚本更容易调试并且更不容易出现令人讨厌的故障模式.

You should declare your variables local inside functions. It is not strictly necessary, but it will make scripts easier to debug and less prone to nasty failure modes when you have several functions with variables of the same name.

我认为HTTP/1.1"是你想要的搜索字符串

I think "HTTP/1.1" is the search string you want

如果性能是一个问题,您应该尝试不同的文本匹配方法(即 Bash 正则表达式 =~grep),看看哪种方法最适合您数据.

If performance is a concern, you should try different approaches to text matching (i.e. Bash regexes =~, grep) to see which is best for your data.

请注意,上面的脚本可以简化为:

Please note that the script above could be simplified by :

  • shift 2
  • 替换local -a command=("${@:3}")
  • 在任何使用它的地方用 "$@" 替换 "${command[@]}"

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

In this case it would make sense, but I used this opportunity to illustrate how building commands as arrays works, as it is often useful in scripts, but in simple cases using positional arguments instead works very well and improves readability.

这篇关于如何编写一个 Bash 函数来测试执行命令的输出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆