Searching max

Basically I have a file num1 which contains IP addresses
[/CODE]
I need to find max element of third number in IP address which is 25! And after that relating to max third number I need to find max fourth number which is 237 (6th line)

Please use code tags as required by forum rules!

Try

sort -nrt"." -k3,3 -k4,4 file | { IFS="." read A B C D; printf "%s %s\n" $C, $D; }
25, 237

An awk solution:

awk '($3 > maxoct3) { maxoct3 = $3; maxoct4 = $4 }
$3 ~ maxoct3 && ($4 > maxoct4) { maxoct4 = $4 }
END {printf "xxx.xxx.%s.%s\n", maxoct3, maxoct4}' FS=. ips.txt

@CarloM: I think he/she wanted the maxoct4 of all lines with maxoct3. If there were a line e.g. x.x.21.238 BEFORE maxoct3, that awk would print xxx.xxx.25.238, which is not contained in the input file.

1 Like

RudiC,
You're obviously correct. But, we could use CarloM's approach to the problem to avoid the need to sort the input:

awk -F '[.]' '
$3 > m3 {m3 = $3; m4 = $4; next}
$3 == m3 && $4 > m4 {m4 = $4}
END {print "xxx.xxx." m3 "." m4}
' num1

As always, if someone wants to try this on a Solaris/SunOS system, they need to use /usr/xpg4/bin/awk , /usr/xpg6/bin/awk , or nawk instead of awk .

1 Like

What if each of these IPs contains in each file?

Oops. That was my intention, but I neglected to reset maxoct4, as in Don's corrected version.

Do you want to maximum over all files? Just pass all the filenames to the awk (or sort) command.

There are several problems here, including, but not necessarily limited to:

  1. Sorting a file alphanumerically using the entire input line as the only sort key doesn't serve any useful purpose when you're trying to compare numeric values in the 3rd and 4th period separated fields.
  2. Your 1st for loop's do doesn't have a matching done .
  3. The wc -l command in both of your for loops will hang waiting for the user to type in input (since no file operands are given on the command line).
  4. I don't see how counting the number of lines in a file (which is what wc -l does) will be of any use in solving this problem.
  5. In the test command [ $max "$D" > "$lastmax"] you need a space before the closing square bracket.
  6. In both of your test commands, the > operator performs an alphanumeric comparison. You need to use the -gt operator to compare numeric comparisons. (For example the command:
    text if [ "7" > "100 ] then echo "7 is greater than 100" fi
    prints:
    text 7 is greater than 100
    but the command:
    text if [ "7" -gt "100 ] then echo "7 is greater than 100" fi
    produces no output.)

The scripts that RudiC and I provided before should give you alternative solutions to this problem.

I guess i need add smth else .....

sort "/Users/Manu/files/*" | awk '($3 > maxoct3) { maxoct3 = $3; maxoct4 = $4 } $3 ~ maxoct3 && ($4 > maxoct4) { maxoct4 = $4 } END {printf "xxx.xxx.%s.%s\n", maxoct3, maxoct4}' FS=. ips.txt

You don't need the sort with the awk solution - just change ips.txt to /Users/Manu/files/* .

Also, Don's version is more efficient.

No, combining bits and pieces of RudiC's suggested code, and CarloM's (or my corrected version of CarloM's) code gives you a hybrid solution that does runs slower and only considers the contents of one file.

I would still suggest my solution (slightly modified to use your new set of files):

awk -F '[.]' '
$3 > m3 {m3 = $3; m4 = $4; next}
$3 == m3 && $4 > m4 {m4 = $4}
END {print "xxx.xxx." m3 "." m4}
' /Users/Manu/files/*

but I may be biased.

Note that if you did want to sort a list of files in the directory /usrs/Manu/files, you would have to leave off the double quotes in the command:

sort /Users/Manu/files/*

With the command:

sort "/Users/Manu/files/*"

it will only sort the single file named * in that directory or produce a file not found diagnostic if that file doesn't exist.

Thank you, now its clear. One more thing... I want to have a condition statement that if fourth oct of IP is 254 then just make it 0 and increment third oct. So xxx.xxx.3.254 => next xxx.xxx.4.0
I just added condition to awk but it doesnt seem to work...

awk -F '[.]' '
$3 > m3 {m3 = $3; m4 = $4; next}
$3 == m3 && $4 > m4 {m4 = $4}

$m4 ==254 { m4=0; m3 = $m3 +1}

END

 {print "134.123." m3 "." m4}
' /Users/Manu/files/hosts/*

Try something like:

awk -F '[.]' '
$3 > m3 {m3 = $3; m4 = $4; next}
$3 == m3 && $4 > m4 {m4 = $4}
END {   if(m4 == 254) {m4 = 0; m3++}
        print "134.123." m3 "." m4
}' /Users/Manu/files/hosts/*
$m4 ==254 { m4=0; m3 = $m3 +1}

In awk $ is used to access fields, not variables - if m4 is 254, $m4 is a reference to (empty) field 254.

Also, consider what you want to do in this case if octet 3 is already 255.

1 Like

Basically, "awk -F" replaces if-else while for statements right?! And works with data in file (Because -F) Am I right?

Not exactly. The while loop is side effect of the fact that awk reads a line from the input file and performs the actions associated with each set of conditions that match those conditions. So in the awk program:

awk -F '[.]' '
$3 > m3 {m3 = $3; m4 = $4; next}
$3 == m3 && $4 > m4 {m4 = $4}
END {   if(m4 == 254) {m4 = 0; m3++}
        print "134.123." m3 "." m4
}' /Users/Manu/files/hosts/*

Notes:

  1. The 1st line of this shell script says that we are going to use the awk utility to process an awk script, sets the field separator to the period character ( -F '[.]' , and the trailing single quote starts the awk script that specifies how awk will process the files it reads.
  2. The 2nd line in the script checks to see if the 3rd field in the current line is greater than the current value of m3 (which has the initial value 0) and, if it is, sets m3 (the maximum 3rd field value seen) to the value of the 3rd field on this line, sets m4 (the maximum 4th field value seen so far associated with the current 3rd field maximum value) to the value of the 4h field on this line, and skips to the next line without checking any of the other conditions.
  3. The 3rd line in the script checks to see if m3 is equal to the 3rd field in the current line and the 4th field in the current line is greater than the current value of m4 and, if it is, sets m4 to the value of the 4th field on this line.
  4. The END condition on the 4th line is special. It is only true after the end-of-file condition has been reached on all of the input files. The 1st statement in the END section actions checks to see if the largest value found in the 4th field in any line with the largest value in the 3rd field in any line in the file is 254 and, if so, increment the 3rd field max value and set the 4th field max value to 0. Then (whether m3 and m4 were changed or not) prints the output line with the computed m3 and m4 values.
  5. The last line of the script has a closing brace that terminates the END clause, a single quote that terminates the awk script, and a shell pathname matching pattern that will be expanded by the shell to be a list of files to be processed by the awk script.

The if statement in the END clause could be changed to a separate awk statement with the condition and actions:

$3 == m3 && $4 == 254 {m3++; m4 = 0}

but it is more efficient to only test for that condition once in the END clause instead of checking for it on every input line when m4 is set to a new value.

1 Like

A different approach to the original question:

awk -F. '{n=256*$3+$4} n>m{m=n; ip=$0} END{print ip}' file*

output:

134.123.25.237
1 Like

How to make it without awk utility??? is it possible?

Do you read the answers to your thread?

1 Like

Sorry lol ive checked.....Thank you...Sorry for confusion