首先,您不需要将变量名大写。通常,全大写的变量名应该保留给要导出到环境中的变量名,以便其他可执行文件使用。
其次,您使用&&的功能应该可以工作,但在面对可能为空或非数值的状态变量时不是很有弹性。
最后,-a尝试没有成功,因为-a是test /[…];它在括号里。
从根本上说,关于shell中的条件,最重要的一点是它们只是命令。这个if表达式:
if foo; then
echo true
else
echo false
fi
做的事情和这个完全一样:
foo
if [ $? -eq 0 ]; then
echo true
else
echo false
fi
所以if(或while或until)后面的东西可以是任何命令。
这也适用于&&和||操作符:两侧的东西都只是命令。序列foo && bar运行命令foo,然后,只有当该命令以状态0退出时,它才运行bar。(所以它实际上是if foo的缩写;然后酒吧;fi)。类似地,foo || bar运行foo,然后,如果该命令以非零状态退出,则运行bar。(所以它实际上是if !foo;然后酒吧;fi)。
这是很多刚开始编程shell的人忽略的主要问题。shell本身没有表达式,只有要运行的命令。
However, because you so often want to perform comparisons and other operations that would be Boolean expressions in regular non-shell programming languages, there is a special command that you can run to do those. It used to be a separate binary, but these days it's built into the shell. Its real name is test, but it can also be invoked as [, in which case it will complain if its last argument is not a matching ]. The arguments inside the brackets or after test constitute an expression to evaluate, and the test command exits with status 0 if the expression is true, and nonzero if it's false. So it turns the sort of thing that is normally what an if statement expects in other programming languages into a command that you can run, effectively translating it for the shell.
The appearance of [...] can be misleading; it really is parsed just as if it were spelled test, with the same command-line processing as any regular shell command. That means that if you try to compare things using < or > they'll be interpreted as redirects. Try to use ( and ) for grouping and you'll be creating a subshell (and probably generating a syntax error by doing so in the middle of a command's arguments). Try to combine expressions with && and || inside the brackets and you'll be terminating the command early and again triggering a syntax error.
你仍然可以在括号外使用&&和||;此时,您只需运行test命令的多个实例,而不是一个实例。但你也可以使用-a和-o只要它们在括号内。所以这两个管道产生了相同的结果:
[ "$status" -ne 200 -a "$string" != "$value" ]
[ "$status" -ne 200 ] && [ "$string" != "value" ]
不同之处在于,第一个命令全部由test命令的一个实例检查,而第二个命令运行其中的两个实例。
The Korn Shell introduced a new version of the test command spelled with two brackets instead of one, between which lies a special syntactic environment that is not parsed the same as a regular command. Between the double brackets you can safely use unquoted parameter expansions, unquoted parentheses for grouping, < and > for string comparison (stick to -lt and -gt to compare numerically), and && and || as Boolean operators. [[...]] also adds the ability to match against glob patterns ([[ foo == f* ]]) and regular expressions ([[ foo =~ ^f ]]).
现代shell(如Bash和Zsh)从Ksh继承了这个构造,但它不是POSIX规范的一部分。如果您所处的环境必须严格遵循POSIX,那么请远离它;否则,基本上就取决于个人喜好了。
注意,算术替换表达式$((…))是POSIX的一部分,它具有与[[…]]非常相似的规则。主要的区别是相等和不相等测试(这里产生一个数值,0表示false, 1表示true)是按数字而不是按字符串完成的:[[10 < 2]]是真,但是$((10 < 2))产生0。
Here again, modern shells have expanded upon the POSIX spec to add a standalone $-less version of ((...)) that functions as basically an autoquoted let command, which you can use in if expressions if you're dealing with numbers. So your first condition could also be written (( status != 200 )). Again, outside of having to stick to POSIX, that's down to personal preference. I like using ((...)) whenever I'm dealing with numbers, but others prefer to just stick to [ or [[ and use the numeric operators like -lt.
因此,无论如何,以下是我重写代码的方法:
website=domain.example
subject="$website DOWN!"
email=an@email.example
value="string_to_search"
status=$(curl -sI "$website" | awk '/HTTP\/1.1/ { print $2 }')
string=$(curl -s "$website" | grep -o "$value")
if (( status != 200 )) && [[ $string != $value ]]; then
mail -s "$subject" "$email" <<<"Website: $website is down, status code: '$status' - $(date)"
fi