LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Bash Script Problem (https://www.linuxquestions.org/questions/programming-9/bash-script-problem-4175657981/)

Scrag 07-24-2019 04:34 PM

Bash Script Problem
 
Hello Everybody,

Below is the bash script I'm working on.

Code:

#!/bin/bash

GREEN='\033[0;32m'              #Setup green color to be used in echo commands
NC='\033[0m'                    #This changes color back to normal or no color
RED='\033[0;31m'                #Setup red color to be used in echo statements
YELLO='\033[0;93m'
WHITE='\033[0;97m'


declare -a info
echo ""

for sub in $(cat $1);do
        echo -e "${YELLO}DOMAIN: $WHITE$sub $NC"
        host $sub.$2
        echo ""
        info=(`host $sub.$2 | grep "has address" | cut -d" " -f4`)
        for i in "${info[@]}"; do
                echo -e "$WHITE $i $NC";
                OpenPort=`masscan "$i" -p0-65535 --rate 100000 2>/dev/null | cut -d' ' -f4`
                for x in "$OpenPort"; do
                        echo -e "        |-- ${GREEN}$OpenPort $NC"
                done
        done
        echo ""
done

What it does is it takes in a txt file of domains and then uses the linux host command to print out the discovered IP's. Then it scans the discovered IP's with masscan and prints the ports. It is not pretty but it works and I am a noob.

My problem is in the formatted output. The first port scanned prints in this format: |-- Port in green. But the 2nd port prints in green but not indented and without the preceeding |--

Like so.....

OUTPUT
Code:

root@localhost:~/RECON-master$ ./host-list.sh all.txt
DOMAIN: 1l-api.mail.ru
1l-api.mail.ru has address 195.211.21.5
1l-api.mail.ru has address 195.211.21.6
1l-api.mail.ru mail is handled by 10 mail.terrhq.ru.

        195.211.21.5
          |-- 80/tcp
443/tcp
        195.211.21.6
          |-- 443/tcp
80/tcp

I would like it to print out like below and cant figure out what the issue is

PREFERRED OUTPUT:
Code:

root@localhost:~/RECON-master$ ./host-list.sh all.txt
DOMAIN: 1l-api.mail.ru
1l-api.mail.ru has address 195.211.21.5
1l-api.mail.ru has address 195.211.21.6
1l-api.mail.ru mail is handled by 10 mail.terrhq.ru.

        195.211.21.5
          |-- 80/tcp
          |-- 443/tcp
        195.211.21.6
          |-- 443/tcp
          |-- 80/tcp


individual 07-24-2019 07:28 PM

Your problem is the following loop.
Code:

for x in "$OpenPort"; do
    ...
done

By quoting $OpenPort, it isn't being split into individual strings, meaning the loop runs once.
EDIT: It doesn't look like you're using x, which is also why you're seeing the ports printed as one string. You need to use $x to print each port.

Scrag 07-24-2019 08:05 PM

Got it.

Thanks again,
Scrag

pan64 07-25-2019 01:49 AM

you might want to use shellcheck to check your script. That will give you some hints

grail 07-25-2019 02:05 AM

You seem to have your solution, so I thought I would give you some feedback on the script:

1. Right now the script is fresh in your mind, but several months away it may not be, so I would suggest adding in something to advise what the script requires on the command line to be passed in
so $1 and $2 make some sense

2. Further to the above, if you assign those values to variables with meaningful names, it will also help in knowing what is required

3. If this script is to be used by others (or again you later on), do not use a for loop or unnecessary 'cat' to read files. A while loop is better suited in case the data in the files might change format

4. Quote all variables until you find a reason not to, as per solution provided by individual

5. Back ticks are old and not as versatile as $() which can be easily nested as required

6. Another easy solution to your problem would have been to make OpenPort an array like you did 'info' (this helps with the for loop and not the fact that you did not use the correct variable inside the loop)

7. You could look into reducing your grep/cut to use maybe sed or awk


Hope some of that helps :) Of course you are free to ignore it all ;)

Scrag 07-25-2019 09:34 AM

Quote:

Originally Posted by grail (Post 6018410)
You seem to have your solution, so I thought I would give you some feedback on the script:

1. Right now the script is fresh in your mind, but several months away it may not be, so I would suggest adding in something to advise what the script requires on the command line to be passed in
so $1 and $2 make some sense

2. Further to the above, if you assign those values to variables with meaningful names, it will also help in knowing what is required

3. If this script is to be used by others (or again you later on), do not use a for loop or unnecessary 'cat' to read files. A while loop is better suited in case the data in the files might change format

4. Quote all variables until you find a reason not to, as per solution provided by individual

5. Back ticks are old and not as versatile as $() which can be easily nested as required

6. Another easy solution to your problem would have been to make OpenPort an array like you did 'info' (this helps with the for loop and not the fact that you did not use the correct variable inside the loop)

7. You could look into reducing your grep/cut to use maybe sed or awk


Hope some of that helps :) Of course you are free to ignore it all ;)

Thanks for the advice - its really helpful.

Scrag

MadeInGermany 07-26-2019 12:29 AM

Deleted.

MadeInGermany 07-26-2019 12:30 AM

One comment:
the quotes in
Code:

for i in "${info[@]}"; do
are correct because they prevent a "word split on $IFS" (and $IFS defaults to whitespace), but the @ in ${ } is special - it still splits on the array members.
But if you have a simple variable and you want to split on the whitespace in the $variable then you cannot use the protecting quotes.
Code:

for x in $OpenPort; do
Not protecting with quotes also have the effect of doing a glob match against files. Ensure there a no * or other glob characters in the $variable! Or turn these glob matches off with
Code:

set -f

rnturn 08-04-2019 06:05 PM

Quote:

Originally Posted by grail (Post 6018410)
Right now the script is fresh in your mind, but several months away it may not be, so I would suggest adding in something to advise what the script requires on the command line to be passed in

Or... look into getopt(1) with a simple example being something like:
Code:


...

function usage() {
    echo "Usage: $0  --in=input --out=output [--debug] [--help]" 1>&2
    exit 1
}

...


OPTS=$( getopt --options '' --longoptions debug,help,in:,out: -n 'getopt_test' -- "$@" )

if [ $? != 0 ] ; then echo "Invalid switch." >&2 ; exit 1 ; fi

eval set -- "$OPTS"

DEBUG=FALSE
IN="undefined"
OUT="undefined"

while true; do
    case "$1" in
        --debug ) DEBUG=TRUE; shift ;;
        --help )  usage; exit ;;
        --in )    IN="$2"; shift 2 ;;
        --out )  OUT="$2"; shift 2 ;;
        -- )      shift; break ;;
        * )      break ;;
    esac
done

[ ${DEBUG} == "TRUE" ] && echo "DEBUG is enabled"
echo IN=$IN
echo OUT=$OUT
...

I always forget the details of how getopt(1) works so I keep the above in a file that I can include while writing shell scripts and have similar snippets for Perl and Python. (Handy things to have available for quick use.) You just have to make sure you keep the usage() function and the actual command line switches in sync.


All times are GMT -5. The time now is 06:40 AM.