4
\$\begingroup\$

Here is my code to find the details of the domain. The domain can be feed as following:

bash script.sh domain1.com domain2.com
bash script.sh domains.txt <-- not completed

The output should be in following format:

IP Address: 192.168.101.2
Server Name: servername.com
NS1: ns1.ournameserver.com
NS2: ns2.ournameserver.com
NS3: ns3.ournameserver.com
Datacenter: datacenter-name
Region: datacenter-13
Server Role: cPanel Web Server
Env: Production
Owner: xxxxxxxxxxx
Status: Active

IP Address: 192.168.101.2
Server Name: servername
NS1: ns1.ournameserver.com
NS2: ns2.ournameserver.com
NS3: ns3.ournameserver.com
Datacenter: datacenter-name
Region: datacenter-13
Server Role: cPanel Web Server
Env: Production
Owner: xxxxxxxxxxx
Status: Suspended

If it is in cloudflare:

Domain name: test.com
IP Address: 192.168.101.1
Server ID: N/A
Server Name: N/A
NS1: LYNDA.CLOUDFLARE.COM
NS2: DYN.CLOUDFLARE.COM
Datacenter: OVH
Region: HETZ-C3
Server Role: cPanel Web Server
Env: Production
Owner: xxxxxxxxxxx

Now it is only giving result in normal format, it also needs to be in JSON format

script.sh

#!bin/bash
HIP="$@"
check ()
{
    regexp="^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$"
    nameserver=('@ns1.ournameserver.com' '@ns2.ournameserver.com' '@ns3.ournameserver.com')

    for j in ${nameserver[@]}
       do
          IPADD=`dig $j $i +noall +answer | grep "A" | awk '{print $5}'`
          if [[ $IPADD =~ $regexp ]]
            then
                echo "IP Address = " $IPADD
                ServerName=`nslookup $IPADD | grep -o -P '(?<=\=).*(?=.)'`
                echo "ServerName = " $ServerName
                DATA=`whois $IPADD | egrep 'org-name|OrgName' | awk '{print $2.$3}'`
                echo "Data Center = " $DATA
                break
          fi
       done
}

check2 ()
{
    Pinging=`ping $i -c 1 | grep 'from' | cut -d$' ' -f4-5| tr '\(|\)' ' '`
    IPADD=`awk '{print $2}' <<< $Pinging`
    echo "IP Address = " $IPADD
    ServerName=`awk '{print $1}' <<< $Pinging`
    echo "Server Name = " $ServerName
}

for i in ${HIP[@]} 
do
    echo "Domain Name = " $i;
    nsserver=`nslookup -type=ns $i | grep 'nameserver' |  grep -o -P '(?<=ns.).*(?=.)' | head -n 1`
    if [[ $nsserver == 'cloudflare.com' ]]
    then
            check
        if ! [[ $IPADD =~ $regexp ]]
        then
                echo "This Domain does not belong to this server."
        fi
    else
        check2
    fi

    whois $i | grep "Registrant Name"
    nslookup -type=ns $i | grep nameserver | awk '{print $2,$3,$4}'
    var=`curl -sL $i | grep '<title>' | tr -d ' ' | grep -o -P '(?<=Account).*(?=ed)'`
    if [[ $var == 'Suspend' ]]
        then
        echo "Status = Account Suspended"
        else
        var=`curl -I $i 2>/dev/null | head -n 1 | cut -d$' ' -f2-3`
        echo "Status = " $var
    fi
    printf '%*s' 100 | tr ' ' '#'
    echo ''

done
\$\endgroup\$

2 Answers 2

4
\$\begingroup\$

Shellcheck reports quite a few issues you might want to correct:

shellcheck -f gcc  197939.sh
197939.sh:2:5: warning: Assigning an array to a string! Assign as array, or use * instead of @ to concatenate. [SC2124]
197939.sh:5:24: note: Backslash is literal in "\.". Prefer explicit escaping: "\\.". [SC1117]
197939.sh:5:36: note: Backslash is literal in "\.". Prefer explicit escaping: "\\.". [SC1117]
197939.sh:5:48: note: Backslash is literal in "\.". Prefer explicit escaping: "\\.". [SC1117]
197939.sh:8:14: error: Double quote array expansions to avoid re-splitting elements. [SC2068]
197939.sh:10:17: note: Use $(..) instead of legacy `..`. [SC2006]
197939.sh:10:22: note: Double quote to prevent globbing and word splitting. [SC2086]
197939.sh:10:25: note: Double quote to prevent globbing and word splitting. [SC2086]
197939.sh:13:38: note: Double quote to prevent globbing and word splitting. [SC2086]
197939.sh:14:28: note: Use $(..) instead of legacy `..`. [SC2006]
197939.sh:14:38: note: Double quote to prevent globbing and word splitting. [SC2086]
197939.sh:15:38: note: Double quote to prevent globbing and word splitting. [SC2086]
197939.sh:16:22: note: Use $(..) instead of legacy `..`. [SC2006]
197939.sh:16:29: note: Double quote to prevent globbing and word splitting. [SC2086]
197939.sh:16:38: note: egrep is non-standard and deprecated. Use grep -E instead. [SC2196]
197939.sh:17:39: note: Double quote to prevent globbing and word splitting. [SC2086]
197939.sh:25:13: note: Use $(..) instead of legacy `..`. [SC2006]
197939.sh:25:19: note: Double quote to prevent globbing and word splitting. [SC2086]
197939.sh:26:11: note: Use $(..) instead of legacy `..`. [SC2006]
197939.sh:26:33: note: Double quote to prevent globbing and word splitting. [SC2086]
197939.sh:27:26: note: Double quote to prevent globbing and word splitting. [SC2086]
197939.sh:28:16: note: Use $(..) instead of legacy `..`. [SC2006]
197939.sh:28:38: note: Double quote to prevent globbing and word splitting. [SC2086]
197939.sh:29:27: note: Double quote to prevent globbing and word splitting. [SC2086]
197939.sh:32:10: error: Double quote array expansions to avoid re-splitting elements. [SC2068]
197939.sh:34:27: note: Double quote to prevent globbing and word splitting. [SC2086]
197939.sh:35:14: note: Use $(..) instead of legacy `..`. [SC2006]
197939.sh:35:33: note: Double quote to prevent globbing and word splitting. [SC2086]
197939.sh:47:11: note: Double quote to prevent globbing and word splitting. [SC2086]
197939.sh:48:23: note: Double quote to prevent globbing and word splitting. [SC2086]
197939.sh:49:9: note: Use $(..) instead of legacy `..`. [SC2006]
197939.sh:49:19: note: Double quote to prevent globbing and word splitting. [SC2086]
197939.sh:54:13: note: Use $(..) instead of legacy `..`. [SC2006]
197939.sh:54:22: note: Double quote to prevent globbing and word splitting. [SC2086]
197939.sh:55:26: note: Double quote to prevent globbing and word splitting. [SC2086]

Additionally, I recommend making regexp, nameserver, IPADD, ServerName and DATA local within check() (and giving most of them better names, or inlining the single-use ones), and making Pinging, IPADD and ServerName local within check2():

check ()
{
    local regexp='^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'
    local nameserver=('@ns1.ournameserver.com' '@ns2.ournameserver.com' '@ns3.ournameserver.com')

    for j in "${nameserver[@]}"
    do
        local IPADD
        IPADD=$(dig "$j" "$i" +noall +answer | grep "A" | awk '{print $5}')
        if [[ $IPADD =~ $regexp ]]
        then
            echo "IP Address = $IPADD"
            echo "ServerName = $(nslookup "$IPADD" | grep -o -P '(?<=\=).*(?=.)')"
            echo "Data Center = $(whois "$IPADD" | grep -E 'org-name|OrgName' | awk '{print $2.$3}')"
            break
        fi
    done
}

check2 ()
{
    local Pinging
    Pinging=$(ping "$i" -c 1 | grep 'from' | cut -d$' ' -f4-5| tr '\(|\)' ' ')
    echo "IP Address = $(awk '{print $2}' <<<"$Pinging")"
    echo "Server Name = $(awk '{print $1}' <<<"$Pinging")"
}

Prefer to pass "$i" as an argument to check(), rather than communicating via global variables. And communicate the $IPADD from the last successful nameserver by other means.

Instead of extracting substrings using grep, then testing them with [[ =~ ]], simply use grep -q for the test.

Improved code

There's still plenty left to work on (for example, repeated whois invocations).

#!/bin/bash

check ()
{
    local regexp='^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'
    local nameserver=('ns1.ournameserver.com' 'ns2.ournameserver.com' 'ns3.ournameserver.com')

    for j in "${nameserver[@]}"
    do
        local IPADD
        IPADD=$(dig "@$j" "$1" +noall +answer | grep -w 'A' | awk '$4=="A" {print $5}')
        if [[ $IPADD =~ $regexp ]]
        then
            echo "IP Address = $IPADD"
            echo "ServerName = $(nslookup "$IPADD" | grep -o -P '(?<=\=).*(?=.)')"
            echo "Data Center = $(whois "$IPADD" | grep -E 'org-name|OrgName' | awk '{print $2.$3}')"
            return 0
        fi
    done
    return 1
}

check2 ()
{
    local Pinging
    Pinging=$(ping "$1" -c 1 | grep 'from' | cut -d$' ' -f4-5| tr '()' ' ')
    echo "IP Address = $(awk '{print $2}' <<<"$Pinging")"
    echo "Server Name = $(awk '{print $1}' <<<"$Pinging")"
}

for i in "$@"
do
    echo "Domain Name = $i"
    if nslookup -type=ns "$i" | grep -q 'nameserver.*cloudflare.com'
    then
        check "$i" || echo "This Domain does not belong to this server."
    else
        check2 "$i"
    fi

    whois "$i" | grep "Registrant Name"
    nslookup -type=ns "$i" | grep nameserver | awk '{print $2,$3,$4}'
    if curl -sL "http://$i" | grep -q '<title>.*Account.*Suspended'
    then
        echo "Status = Account Suspended"
    else
        echo "Status = $(curl -I "$i" 2>/dev/null | head -n 1 | cut -d$' ' -f2-3)" 
    fi
    printf '%*s\n' 100 | tr ' ' '#'
done
\$\endgroup\$
1
\$\begingroup\$

@Toby left some room for teamwork :-) Here are some extra points on top of his excellent review.

Naming

Some of the names are very poor, notably check, check2 and i as a global variable. i is perfectly fine as a counter in a counting loop, otherwise not. It would be good to replace all these names with something that describes their purpose.

Also, the convention is to use lowercase names, instead of capitalizing as in Pinging (which by the way another example of a poor name).

Lastly, names with all capital letters should only be used for system variables or exported variables.

Define constants at the top

It seems this constant defined in check is quite important for the behavior if the script:

nameserver=('@ns1.ournameserver.com' '@ns2.ournameserver.com' '@ns3.ournameserver.com')

It would be better to define at the top of the script where it's easier to see and modify.

Use $(...) instead of backticks

The `...` syntax is obsolete.

Avoid long pipelines when possible. Use $(...) instead.

Long pipelines with many processes are what slow down shell scripts. It's good to make a habit to avoid them. Take for example:

IPADD=`dig $j $i +noall +answer | grep "A" | awk '{print $5}'`

Here, the grep process can be easily eliminated, since awk can perform the same function:

IPADD=$(dig $j $i +noall +answer | awk '/A/ {print $5}')

Furthermore, you use the result to match against a regular expression. Awk can do that too, and probably more efficiently than Bash.

IPADD=$(dig $j $i +noall +answer | awk '/A/ && $5 ~ /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/ {print $5}')

Now in Bash you can simply check if the variable is empty is not.

Iterating over arrays

This is the correct way to iterate over elements of an array:

for item in "${are[@]}"; do ...; done

That is, the double quotes around the array are important, in case the items may contain spaces. Even if you know for sure there won't be spaces in your values, it's good to adopt to writing style so that it becomes a good habit.

Extracting multiple values

This code extracts two values from the output of a command:

Pinging=`ping $i -c 1 | grep 'from' | cut -d$' ' -f4-5| tr '\(|\)' ' '`
IPADD=`awk '{print $2}' <<< $Pinging`
echo "IP Address = " $IPADD
ServerName=`awk '{print $1}' <<< $Pinging`
echo "Server Name = " $ServerName

Another way using read:

read ip servername < <(ping $i -c 1 | grep 'from' | cut -d$' ' -f4-5| tr '\(|\)' ' ' | awk '{ print $2, $1 }')

The advantage is one less awk process. Note that <(...) is Bash 4 syntax. If it's not available in your version, then you can save the result of the input process in a variable, and then use a here-string instead.

result=$(ping $i -c 1 | grep 'from' | cut -d$' ' -f4-5| tr '\(|\)' ' ' | awk '{ print $2, $1 }')
read ip servername <<< "$result"
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.