-5

I have CSV file with IP addresses and open ports:

IP,1,3,4,6,7,9,13,17,19,20,21,22,23,24,25,26
1.1.1.2,,,,,,,,,,,open,,,,,
1.1.1.3,,,,,,,,,,,open,,,,,
1.1.1.4,,open ,open,,,,,,,,open,,,,,
1.1.1.5,,,,,,,,,,,open,,,,,
1.2.3.4,,,,,,,,,,,open,,,,,
1.4.5.6,,,,,open,,,,,,open,,,,,
1.4.5.6,,,,,,,,,,,open,,,,,
1.1.3.4,,,,,,,,,,,open,,,,,

For each IP address with an open port, I need to execute a command using both the IP address and the port number of the open port (taken from the CSV header).

Kusalananda
  • 333,661
  • 1
    Will the command that you execute for each IP with open ports have to use the corresponding port number? Is the port number the number listed in the CSV header? – Kusalananda Mar 29 '19 at 16:38
  • @Kusalananda exactly!! – biniyam getu Mar 29 '19 at 16:40
  • 1
    and thankyou for helping me edit my question @Kusalananda and you understood my question, – biniyam getu Mar 29 '19 at 16:44
  • 2
    I'll pass on this particular question, thank you; but if I was to answer, I would want to know what command you're executing, so that it's clear how the port should be portrayed. I think that'd make the answer more useful to you. I'd also be curious if the number of possible ports ends at 26 or could go up to 65,535? Also, would there only ever be one open port? Could there be zero or more than one? – Jeff Schaller Mar 29 '19 at 16:52
  • @JeffSchaller command is telnet and port number is not upto 65,535 but i have more than 900 ports and there status will change every time with the scan. what i want to achieve is to check if there is any active telnet session listening but I just need the help in picking IP and port number that is open – biniyam getu Mar 29 '19 at 17:31

2 Answers2

1

Solving this competely in pure bash would, I think, not be advisable. See e.g. the question "Why is using a shell loop to process text considered bad practice?".

Instead, let's make the input data a bit easier to digest.

awk 'FNR == 1 { split($0, port, ","); FS=","; next }
              { for (i=2; i<=NF; ++i) if ($i == "open") print $1, port[i] }' file.csv

This awk command would first read the port numbers from the first line of the CSV file into an array called port. The port number for column N would be stored in port[N].

It does this by splitting the first line of the input on commas and simply storing the result in the port array. This is what the split() command does. The condition FNR == 1 means "If this is the first line of the file, then do this..." (FNR is the line number in the current input file). A code block with no condition on it will be executed for each line of input.

After calling split(), FS, the field separator, is set to a comma. This means that the other lines in the file will automatically be split on commas into fields. This is used in the loop in the second block to loop over the CSV fields (from the second field to the last) on each line.

For each of the other rows in the data, it loops through the comma-delimited fields, and when it finds a field whose value is the string open, it prints out the IP address (the first field) and the corresponding port number.

The output from this command, given the data in the question is

1.1.1.2 21
1.1.1.3 21
1.1.1.4 4
1.1.1.4 21
1.1.1.5 21
1.2.3.4 21
1.4.5.6 7
1.4.5.6 21
1.4.5.6 21
1.1.3.4 21

This can easily be read by a loop in the shell:

while read -r ip port; do
    telnet "$ip" "$port"    # or whatever your command is
done

This reads the IP address and port number, one by one.

To combine these into a complete script:

#!/bin/sh

awk 'FNR == 1 { split($0, port, ","); FS=","; next }
              { for (i=2; i<=NF; ++i) if ($i == "open") print $1, port[i] }' file.csv |
while read -r ip port; do
    telnet "$ip" "$port"    # or whatever your command is
done

The output of the awk command is piped to the while loop which reads the values and calls the command (note the | pipe after the input filename).

Note that if an IP address has more than one port open, the command will be executed multiple times for that address.

Kusalananda
  • 333,661
  • OMG this was what i was trying to do, this is amazing. I am dumb Can you please help me understand this more (can you tell me in debugging mode? ) – biniyam getu Mar 29 '19 at 17:41
  • @biniyamgetu I need to know exactly what I need to explain. – Kusalananda Mar 29 '19 at 17:46
  • Bro I am really thankful , this is so helpful...so, what is FNR==1 doing, then I see split and what is FS – biniyam getu Mar 29 '19 at 17:53
  • @biniyamgetu Hold on, I will add some extra text about those things. – Kusalananda Mar 29 '19 at 17:55
  • 1
    you are genius, and it is doing what i wanted to do...Thank you sir!! – biniyam getu Mar 29 '19 at 17:58
  • hey @Kusalananda IDK if you will get this but my while loop is not breaking out of the first iteration? – biniyam getu Apr 01 '19 at 19:35
  • @biniyamgetu I'm assuming that you mean that your loop gets stuck on the first call to telnet? Well, if a connection is established, telnet will be connected until you disconnect. If this is the issue, you may want to ask a separate question about how to test whether a port on a host is open or not. You may also want to try nmap in place of telnet. This part of the question was not really central to the current question. – Kusalananda Apr 01 '19 at 19:39
  • No, I am talking about the for loop iteration. The while loop is not breaking out of the first iteration which is the first IP. – biniyam getu Apr 03 '19 at 11:30
  • @biniyamgetu Exactly. This is because telnet does not terminate when it successfully connects to a port on a host. It has nothing to do with the for loop in the awk program (this loop is unable to progress because tho while loop does net get past the first iteration, because telnet successfully connected to a host). You may possibly investigate some other mechanism to check whether a port on a remote host is open. – Kusalananda Apr 03 '19 at 11:39
  • I understood what you are saying. you know what? It is the same thing but the other way round...The while loop is failing when telnet responds with error...Thanks tho, – biniyam getu Apr 04 '19 at 12:07
  • @biniyamgetu There may be a timeout that telnet has to wait for before continuing with the next host, if one host is not responding on a particular port, but once it times out, the loop will continue. It will not break out of the loop if you run it the way I've outlined in my answer. – Kusalananda Apr 04 '19 at 12:13
-1

Select your first and next respective fields using awk.

awk -d "," -F '{print $1, $n...}
jimmij
  • 47,140
Sunil
  • 7
  • This doesn't yet address executing a command or using the ports. For the future, when questions are undergoing heavy commenting and editing, I'd suggest waiting for the requirements to settle down before attempting an answer. – Jeff Schaller Mar 29 '19 at 16:42