I'm trying to create a simple Bash script to check if the website is down and for some reason the "and" operator doesn't work:
#!/usr/bin/env bash
WEBSITE=domain.example
SUBJECT="$WEBSITE DOWN!"
EMAILID="an@email.example"
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
The "-a" operator also doesn't work:
if [ $STATUS -ne 200 ] -a [[ "$STRING" != "$VALUE" ]]
Could you also please advise when to use:
?
If $STATUS
expands to the empty string, then
if [ $STATUS -ne 200 ]
is invalid because it is equivalent to
if [ -ne 200 ]
, which should generate an error similar to "-ne: unary operator expected".
The command
if [ $STATUS -ne 200 ] -a [[ "$STRING" != "$VALUE" ]];
is invalid regardless of the expansion of $STATUS
because it is passing [[
and ]]
as arguments to the [
command, but [
requires that its last argument be the literal string ]
. It would probably be better to do:
if ! [ "${STATUS}" -eq 200 ] 2> /dev/null && [ "${STRING}" != "${VALUE}" ]; then ...
or
if [ "${STATUS}" != 200 ] && [ "${STRING}" != "${VALUE}" ]; then ...
In each of these, ]
is the final argument to the invocation of [
, as required. The shell parses &&
and ;
as tokens which terminate the [
command, but strings like -a
, [[
, and ]]
are just strings that the shell passes to the command. (In the first case, the shell treats 2> /dev/null
as a redirection operator, so those strings are not passed to [
as arguments). Note that using -a
as an argument to [
as a boolean AND is considered bad practice, and ought to be avoided.
[
and [[
are very different, but the only difference between [
and test
is that [
requires that its final argument be ]
and test
does not. (Some will argue that another difference is that [
is a builtin but test
is not, and although there may have been a time in the distant past when some shells had [
as a builtin while test
was always an invocation of /bin/test
, that probably has not been the case in any common shell for decades). Another reasonable solution is:
if test "${STATUS}" != 200 && test "${STRING}" != "${VALUE}"; then ...
Personal opinion: never use [[
. It suppresses important error messages and is not portable to different shells. Also, as seen by the existence of this question, it is confusing. One may argue that the confusion here is caused by the shell's grammar and obscure behavior of [
, and I would agree. [
is also confusing. You can prevent a lot of confusion if you avoid both [[
and [
, and always use test
.