简体   繁体   中英

Bash script if/then with multiple conditions

I want to print out the hostname and CNAME only if DNS status is: "NXDOMAIN" OR "SERVFAIL" AND has a "CNAME".

Conditions:

dig @8.8.8.8 -t A ${hstnm} | grep -q 'NXDOMAIN'
dig @8.8.8.8 -t A ${hstnm} | grep -q 'SERVFAIL'
dig @8.8.8.8 -t CNAME $hstnm +short >/dev/null

So I wrote below bash script but it does not work, any help is very much appreciated, thank you.

for hstnm in $(cat /path/file.txt)
do
if dig @8.8.8.8 -t A ${hstnm} | grep -q 'NXDOMAIN' || dig @8.8.8.8 -t A ${hstnm} | grep -q 'SERVFAIL' && dig @8.8.8.8 -t CNAME $hstnm +short >/dev/null ]]
then
echo -n -e "\e[92mNXDOMAIN: \e[0m${hstnm} "
echo -n -e "\e[93mCNAME: \e[0m"; dig @8.8.8.8 -t CNAME $hstnm +short
echo
fi
done

OK, let's label your conditions:

  • A is dig @8.8.8.8 -t A "$hstnm" | grep -q 'NXDOMAIN' dig @8.8.8.8 -t A "$hstnm" | grep -q 'NXDOMAIN'
  • B is dig @8.8.8.8 -t A "$hstnm" | grep -q 'SERVFAIL' dig @8.8.8.8 -t A "$hstnm" | grep -q 'SERVFAIL'
  • C is dig @8.8.8.8 -t CNAME "$hstnm" +short >/dev/null

Now, with those names, tell us in algorithmic language what test you want.
Also, we need to know the shell you are using (BASh? Korn? Almiquish? Z?)
Depending on these parameters, we may provide a better indication. For example

#!/bin/bash

for hstnm in $(cat /path/file.txt)
do
if ( dig @8.8.8.8 -t A "$hstnm" | grep -q 'NXDOMAIN' ) || ( dig @8.8.8.8 -t A "$hstnm" | grep -q 'SERVFAIL' ) && ( dig @8.8.8.8 -t CNAME "$hstnm" +short >/dev/null )
then
echo -n -e "\e[92mNXDOMAIN: \e[0m${hstnm} "
echo -n -e "\e[93mCNAME: \e[0m"; dig @8.8.8.8 -t CNAME "$hstnm" +short
echo
fi
done

assume "A or B then C"...


edit-2020-08-04 OK, what you're trying to achive is "IF (either "A" or "B" is true) and ("C" is true) THEN"
The first part, "either "A" or "B" is true" should translate to A || B A || B ie

if ( dig @8.8.8.8 -t A "$hstnm" | grep -q 'NXDOMAIN' ) || ( dig @8.8.8.8 -t A "$hstnm" | grep -q 'SERVFAIL' )
then
#foo
fi

First, I group "A" and "B" in parentheses...or curly brackets. If I don't proceed so, I change the meaning in a bit surprising way: dig @8.8.8.8 -t A "$hstnm" | grep -q 'NXDOMAIN' || dig @8.8.8.8 -t A "$hstnm" | grep -q 'SERVFAIL' dig @8.8.8.8 -t A "$hstnm" | grep -q 'NXDOMAIN' || dig @8.8.8.8 -t A "$hstnm" | grep -q 'SERVFAIL' dig @8.8.8.8 -t A "$hstnm" | grep -q 'NXDOMAIN' || dig @8.8.8.8 -t A "$hstnm" | grep -q 'SERVFAIL' ask the shell to

  • dig google for the host address, and check if there's a "no such domain" answer.
  • when that check didn't succeed (double pipe), dig google for the same host address and check if there's an "issue reaching the domain name server" answer.
  • but when the first check don't fail, there's no other diging (what is fine), but some shells will continue and pipe the previous output to the grep' command (I didn't check how my bash behaves, but it's not good to rely on such things)...what will lead to a big failure (because we're coming from a silent check, so there's no input in the pipe for the second check to consume)

So you see why the parentheses here. But beware: bourne compatible shells don't have parenthesis for grouping logical operations like many programming languages. In fact, we're not using boolean switching but only the ability of the shell to call a command based on the success or the failure of the previous command (it's not truely-falsy system like seen elsewhere, even when using commands like test ) Despite the resemblance, parentheses group command in a subshell (use curly braces if you don't want to use a subshell and benefit some variables passing up-and-down) When the group is processed, it will have fail or succed as a bloc and have the return code of the last command run in the group.

Now, we may think about using grouping of grouping in order to achive our goals.

if { ( dig @8.8.8.8 -t A "$hstnm" | grep -q 'NXDOMAIN' ) || ( dig @8.8.8.8 -t A "$hstnm" | grep -q 'SERVFAIL' ) } && ( dig @8.8.8.8 -t CNAME "$hstnm" +short >/dev/null )
then
#foo
fi

Frankly, I'm don't know how shells supporte nesting grouping and will never try to found the answer if I'm not forced (you know, when you inherith a script that you have to fix...) I find that difficult to read back and hence to maintain. I prefere to go that other way:

if ( dig @8.8.8.8 -t A "$hstnm" | grep -q 'NXDOMAIN' ) || ( dig @8.8.8.8 -t A "$hstnm" | grep -q 'SERVFAIL' )
then 
  if dig @8.8.8.8 -t CNAME "$hstnm" +short >/dev/null
  then
  #foo
  fi
fi

to be followed.

This is what your post currently says (simplified):

if A || B && C ]]
then
  ...
fi

Simply drop the trailing ]] .

You don't need to add any grouping, since unlike many languages, A || B && C A || B && C in this context in Bash is equivalent to (A || B) && C

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM