Showing posts with label shell. Show all posts
Showing posts with label shell. Show all posts

Friday, February 21, 2014

Convert UTC Date to Seconds

One of the primary ways used to compare dates is to convert the date to seconds and then do the comparison. The GNU date has an option +%s to convert the given date to seconds since epoch. But sometimes GNU date is not available in all the systems and they can't install it due to restrictions in the working environment. The next option is to use strftime() of gawk or perl. The same issue may exist with gawk/perl also, i.e. they may not have the required libs or things of that sort.

The following script which I call utc_to_sec will convert the given UTC date to seconds using the basic arithmetic.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#!/bin/bash
# utc_to_sec v1.0
# Script to convert time to seconds
# TZ should be UTC
#
# ./utc_to_sec 2014-02-20  01:42:02
# 1392860522

EXE=${0#*/}
usage()
{
  echo -e "\nConvert date to seconds since epoch"
  echo "  Usage : $EXE yyyy-mm-dd hh:mm:ss"
  echo -e "  ** TZ default UTC **\n"
  exit
}

do_everything()
{
  echo $1 $2 | awk '

    BEGIN{
      year=hh=1; mon=mm=2; day=ss=3
      m_lo[4]=m_lo[6]=m_lo[9]=m_lo[11]=1
      m_hi[1]=m_hi[3]=m_hi[5]=m_hi[7]=m_hi[8]=m_hi[10]=m_hi[12]=1
    }

    function no_of_days_in_year(input)
    {
      leap=0
      if ( input%4 == 0 ){
        if ( input%100 == 0 ){
          if ( input%400 == 0 ){
            leap=1
          }
        }
        else{
          leap=1
        }
      }

      return (365+leap)
    }

    function no_of_days_in_month(in_mon, in_year)
    {
      if(m_hi[in_mon]) val=31
      else if(m_lo[in_mon]) val=30
      else {
        val= no_of_days_in_year(in_year)>365?29:28
      }
      return val
    }

    function validate(a_date, a_time)
    {
      if( a_date[year]<1970 || a_date[mon]<=0 || a_date[mon]>12 ||
          a_date[day]<=0 || a_date[day]>31 ||
          ( m_lo[a_date[mon]] && (a_date[day]>30) ) ||
          ( a_date[mon]==2 && a_date[day]>29 ) ||
          a_time[hh]<0 || a_time[hh]>23  ||
          a_time[mm]<0 || a_time[mm]>=60 ||
          a_time[ss]<0 || a_time[ss]>=60 ){
        print -1
        exit
      }
      if(no_of_days_in_year(a_date[year])<=365 && a_date[mon]==2 && a_date[day]>28){
        print -2
        exit
      }
    }

    END{
      split($1, a_date, /-/)
      split($2, a_time, /:/)
      validate(a_date, a_time)

      #no of days in a year
      for(i=1970; i<a_date[year]; i++)
        sum_days+=no_of_days_in_year(i)

      for(i=1; i<a_date[mon]; i++)
        sum_days+=no_of_days_in_month(i, a_date[year])

      sum_days=sum_days+a_date[day]-1
      seconds = (sum_days*24*60*60) + (a_time[hh] * 3600) + (a_time[mm] * 60) + a_time[ss]
      print seconds
    }
  '
}

( [[ $# -ne 2 ]] ) && usage
seconds=$( do_everything $* )
[[ ${seconds:-0} -lt 0 ]] && echo "Invalid data..." && usage
echo $seconds

Output

root@maximus:~/scripts# ./utc_to_sec 2037-12-31 23:59:59
2145916799
root@maximus:~/scripts# date +%s -d "2037-12-31 23:59:59 UTC"
2145916799
root@maximus:~/scripts# ./utc_to_sec 2014-02-19 12:13:56
1392812036
root@maximus:~/scripts# date +%s -d " 2014-02-19 12:13:56 UTC"
1392812036
root@maximus:~/scripts# ./utc_to_sec 1970-01-01 00:00:00
0
root@maximus:~/scripts# date +%s -d "1970-01-01 00:00:00 UTC"
0
root@maximus:~/scripts# date +%s -d "1990-01-01 23:40:44 UTC"
631237244
root@maximus:~/scripts# ./utc_to_sec 1990-01-01 23:40:44
631237244

Execution time

root@maximus:~/scripts# time date +%s -d "2037-12-31 23:59:59 UTC"
2145916799

real    0m0.010s
user    0m0.004s
sys     0m0.008s

root@maximus:~/scripts# time ./utc_to_sec 2037-12-31 23:59:59
2145916799

real    0m0.023s
user    0m0.012s
sys     0m0.004s


HTH

Wednesday, January 29, 2014

Determining IP address range from Subnet/CIDR

Script to find the IP address range from the given Subnet.

There are few functions which can be reused like
  1. Convert IP to Decimal ip_to_int()
  2. Convert Decimal to IP int_to_ip()
  3. Netmask to CIDR to_cidr()

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#!/bin/bash
# http://linuxcalling.blogspot.in/
# Script to find the IP address range
# Script : ip_range
# Usage  : ip_range <IP> <Subnet> [0|1 print range]
# Ahamed (ahamed.en@gmail.com)

usage()
{
  EXE=${0#*/}
  echo "Usage: $EXE <IP> <Subnet> [0|1]<print range>"
  echo "   eg: To display the IP address range"
  echo "       $EXE 192.168.1.1 255.255.140.0"
  echo "   eg: To display the IP address range with entire range"
  echo "       $EXE 192.168.1.1 255.255.140.0 1"
  exit
}

[ $# -lt 2 ] && usage

echo $1 $2 $3 | awk '

  BEGIN{
    BITS=8
    mask_add[0]=valid_subnet[0]=0
    for(i=BITS-1;i>=0;i--){
      k=or(k,lshift(1,i))
      mask_add[k]=BITS-i
      valid_subnet[BITS-i]=k
    }
  }
  function validate_subnet(input)
  {
    split(input, oc, ".")

    if(oc[4] > oc[3] || oc[3] > oc[2] || oc[2] > oc[1]){
        print "Invalid Subnet: ",input
        exit
    }
    for(j=1; j<=BITS/2; j++){
      for(i=0;i<=BITS;i++){
        if(!xor(oc[j],valid_subnet[i])){
          break;
        }
        err++
      }
      if(err == (BITS+1)){
        print "Invalid Subnet: ",input
        exit
      }
      err=0
    }
  }

  function to_cidr(input)
  {
    split(input, oc, ".")
    ret=mask_add[oc[1]]+mask_add[oc[2]]+mask_add[oc[3]]+mask_add[oc[4]]
    return ret
  }

  function ip_to_int(input)
  {

    split(input, oc, ".")
    ip_int=(oc[1]*(256^3))+(oc[2]*(256^2))+(oc[3]*(256))+(oc[4])
    return ip_int

  }

  function int_to_ip(input)
  {
    str=""
    num=input
    for(i=3;i>=0;i--){
      octet = int (num / (256 ^ i))
      str= i==0?str octet:str octet "."
      num -= (octet * 256 ^ i)
    }
    return str
  }
  {
    ip=$1
    mask=$2
    range=$3

    validate_subnet(mask)

    cidr=to_cidr(mask)
    diff=32-cidr
    no_of_ip=2^diff

    ip_int=ip_to_int(ip)
    ip_mask=and(ip_int, (2^32 - 2^diff))

    ip_start=ip_mask
    ip_end=ip_mask+no_of_ip-1

    print "No of IPs\t"(no_of_ip-2)
    print "First IP\t" int_to_ip(ip_start+1)
    print "Last IP\t\t" int_to_ip(ip_end-1)
    print "Subnet\t\t" int_to_ip(ip_mask)
    print "Broadcast\t" int_to_ip(ip_end)

    if(range){
      print "\nIP address range -- START --\n"
      curr=ip_start
      i=0
      while(curr<=ip_end){
        printf int_to_ip(curr)"\t"
        if(j++%4 == 0) printf "\n"
        curr+=1
      }
      print "\nIP address range -- END --"
    }
  } '

Script Usage

[root@maximus] → ./ip_range 192.168.1.1 255.255.255.224
No of IPs       30
First IP        192.168.1.1
Last IP         192.168.1.30
Subnet          192.168.1.0
Broadcast       192.168.1.31


[root@maximus] → ./ip_range 192.168.1.1 255.255.255.224 1
No of IPs       30
First IP        192.168.1.1
Last IP         192.168.1.30
Subnet          192.168.1.0
Broadcast       192.168.1.31

IP address range -- START --

192.168.1.0     192.168.1.1     192.168.1.2     192.168.1.3
192.168.1.4     192.168.1.5     192.168.1.6     192.168.1.7
192.168.1.8     192.168.1.9     192.168.1.10    192.168.1.11
192.168.1.12    192.168.1.13    192.168.1.14    192.168.1.15
192.168.1.16    192.168.1.17    192.168.1.18    192.168.1.19
192.168.1.20    192.168.1.21    192.168.1.22    192.168.1.23
192.168.1.24    192.168.1.25    192.168.1.26    192.168.1.27
192.168.1.28    192.168.1.29    192.168.1.30    192.168.1.31

IP address range -- END --

[root@maximus] → ./ip_range 192.168.1.1 255.255.0.0
No of IPs       65534
First IP        192.168.0.1
Last IP         192.168.255.254
Subnet          192.168.0.0
Broadcast       192.168.255.255