HTF*_*HTF 142 bash if-statement
我正在尝试创建一个简单的bash脚本来检查网站是否已关闭,并且由于某种原因"and"运算符不起作用:
#!/usr/bin/env bash
WEBSITE=domain.com
SUBJECT="$WEBSITE DOWN!"
EMAILID="an@email.com"
STATUS=$(curl -sI $WEBSITE | awk '/HTTP\/1.1/ { print $2 }')
STRING=$(curl -s $WEBSITE | grep -o "string_to_search")
VALUE="string_to_search"
if [ $STATUS -ne 200 ] && [[ "$STRING" != "$VALUE" ]]; then
echo "Website: $WEBSITE is down, status code: '$STATUS' - $(date)" | mail -s "$SUBJECT" $EMAILID
fi
Run Code Online (Sandbox Code Playgroud)
"-a"运算符也不起作用:
if [ $STATUS -ne 200 ] -a [[ "$STRING" != "$VALUE" ]]
Run Code Online (Sandbox Code Playgroud)
你能告诉我什么时候使用:
Wil*_*ell 214
你有什么应该工作,除非${STATUS}是空的.这可能会更好:
if ! [ "${STATUS}" -eq 200 ] 2> /dev/null && [ "${STRING}" != "${VALUE}" ]; then
Run Code Online (Sandbox Code Playgroud)
要么
if [ "${STATUS}" != 200 ] && [ "${STRING}" != "${VALUE}" ]; then
Run Code Online (Sandbox Code Playgroud)
很难说,因为你没有告诉我们你的脚本究竟出了什么问题.
个人意见:永远不要使用[[.它不能移植到不同的外壳.
小智 24
试试这个:
if [ $STATUS -ne 200 -a "$STRING" != "$VALUE" ]; then
Run Code Online (Sandbox Code Playgroud)
小智 19
试试这个:
if [ ${STATUS} -ne 100 -a "${STRING}" = "${VALUE}" ]
Run Code Online (Sandbox Code Playgroud)
要么
if [ ${STATUS} -ne 100 ] && [ "${STRING}" = "${VALUE}" ]
Run Code Online (Sandbox Code Playgroud)
Jo *_* So 11
引用:
"-a"运算符也不起作用:
如果[$ STATUS -ne 200] -a [["$ STRING"!="$ VALUE"]]
有关更详细的解释:[并且]没有bash保留字.该if关键字引入到由作业进行评价条件(条件为真,当作业的返回值是0或否则为false).
对于琐碎的测试,有test程序(man test).
由于有些人发现类似行if test -f filename; then foo bar; fi等烦人,在大多数系统上你都会找到一个程序[,这个test程序实际上只是程序的符号链接.当test被称为[,你必须添加]作为最后一个位置参数.
所以if test -f filename基本上是相同的(就产生的过程而言)if [ -f filename ].在这两种情况下,test程序都将启动,并且两个进程的行为应该相同.
这是你的错误:if [ $STATUS -ne 200 ] -a [[ "$STRING" != "$VALUE" ]]将解析if+一些工作,工作除了if自己以外的一切.这个工作只是一个简单的命令(bash代表导致单个进程的事情),这意味着第一个单词([)是命令,其余的是它的位置参数.在第一个之后还有其余的论点].
也不[[是,确实是一个bash关键字,但在这种情况下,它只被解析为一个普通的命令参数,因为它不在命令的前面.
首先,您不需要将变量名称大写。一般来说,全大写变量名应该保留给那些export为了其他可执行文件的利益而被编入环境的变量名。
其次,您所拥有的&&应该可以工作,但是面对可能为空或非数字的状态变量时,它的弹性不是很强。
最后,-a尝试没有成功,因为它是/ ...-a语法的一部分;它位于括号内。test[]
从根本上来说,了解 shell 中的条件最重要的是它们只是命令。这个 if 表达式:
if foo; then
echo true
else
echo false
fi
Run Code Online (Sandbox Code Playgroud)
与此完全相同:
foo
if [ $? -eq 0 ]; then
echo true
else
echo false
fi
Run Code Online (Sandbox Code Playgroud)
if所以(orwhile或)之后的内容until可以是任何命令。
这也适用于&&和||运算符:两边的东西只是命令。该序列foo && bar运行该命令foo,然后,仅当该命令以状态 0 退出时,它才会运行bar。(因此它实际上是 的缩写if foo; then bar; fi。)类似地,foo || bar运行foo,然后,如果该命令以非零状态退出,则运行bar。(所以它实际上是 的缩写if ! foo; then bar; fi。)
这是许多 shell 初学者所忽略的主要事情。shell 本身没有表达式,只有要运行的命令。
但是,由于您经常需要执行比较和其他操作,这些操作在常规非 shell 编程语言中是布尔表达式,因此您可以运行一个特殊的命令来执行这些操作。它曾经是一个单独的二进制文件,但现在它被内置到 shell 中。它的真实名称是test,但它也可以被调用为[,在这种情况下,如果它的最后一个参数不匹配,它将抱怨]。括号内或后面的参数test构成要计算的表达式,如果表达式为 true,则测试命令以状态 0 退出,如果表达式为 false,则以非零状态退出。因此,它将其他编程语言中的语句通常所if期望的内容转换为可以运行的命令,从而有效地将其转换为 shell。
[...的外观]可能会产生误导;它确实被解析,就好像它被拼写一样test,并使用与任何常规 shell 命令相同的命令行处理。这意味着,如果您尝试使用<或 来比较事物>,它们将被解释为重定向。尝试使用(and)进行分组,您将创建一个子 shell(并且可能通过在命令参数中间这样做而生成语法错误)。尝试将表达式与括号内的 和 组合起来&&,||您将提前终止命令并再次触发语法错误。
您仍然可以在括号之外&&使用and ;此时,您只需运行测试命令的多个实例,而不是仅运行一个。但您也可以使用and,只要它们位于括号内即可。所以这两个管道产生相同的结果:|| -a-o
[ "$status" -ne 200 -a "$string" != "$value" ]
[ "$status" -ne 200 ] && [ "$string" != "value" ]
Run Code Online (Sandbox Code Playgroud)
不同之处在于,第一个命令全部由test命令的一个实例检查,而第二个命令则运行其中的两个实例。
Korn Shell 引入了新版本的测试命令,用两个括号而不是一个括号拼写,中间有一个特殊的语法环境,其解析方式与常规命令不同。在双括号之间,您可以安全地使用不带引号的参数扩展、不带引号的括号进行分组、<字符串>比较(坚持-lt和-gt进行数字比较)以及&&作为||布尔运算符。[[...]]还增加了匹配 glob 模式 ( [[foo == f* ]]) 和正则表达式 ( [[ foo =~ ^f ]]) 的能力。
Bash 和 Zsh 等现代 shell 继承了 Ksh 的这种构造,但它不是 POSIX 规范的一部分。如果您处于必须严格遵守 POSIX 的环境中,请远离它;否则,这基本上取决于个人喜好。
请注意,算术替换表达式$((...)) 是[[POSIX 的一部分,并且它的规则与...非常相似]]。主要区别在于相等和不等式测试(此处生成一个数值,0 表示 false,1 表示 true)是以数字方式完成的,而不是字符串方式:[[ 10 < 2 ]]为 true,但 $(( 10 < 2 ))生成 0。
再次强调,现代 shell 在 POSIX 规范的基础上进行了扩展,添加了独立的$-less 版本((... )),其功能基本上是一个自动引用let命令,if如果您正在处理数字,则可以在表达式中使用它。所以你的第一个条件也可以写成(( status != 200 ))。再说一次,除了必须坚持 POSIX 之外,这取决于个人喜好。每当我处理数字时,我喜欢使用((... )),但其他人更喜欢只坚持使用[or[[并使用数字运算符,例如-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
Run Code Online (Sandbox Code Playgroud)