2012-05-26 22 views
8

C'è indirizzo IP: 66.102.13.19, e da questo indirizzo di quello ricevuto questo indirizzoIndirizzo IP Converter

http://1113984275 

Ma come? E come posso farlo con l'aiuto di bash. Ad esempio, lo può fare this service, ma non capisco l'algoritmo.

risposta

30
ip=66.102.13.19 
IFS=. read -r a b c d <<< "$ip" 
printf '%s%d\n' "http://" "$((a * 256 ** 3 + b * 256 ** 2 + c * 256 + d))" 

A proposito, il numero nella tua domanda non corrisponde all'indirizzo IP.

Per convertire un numero decimale in un IP:

#!/bin/bash 
dec2ip() { 
    local ip [email protected] 
    for e in {3..0} 
    do 
     ((octet = dec/(256 ** e))) 
     ((dec -= octet * 256 ** e)) 
     ip+=$delim$octet 
     delim=. 
    done 
    printf '%s\n' "$ip" 
} 

dec2ip "[email protected]" 

Per convertire un IP ad un decimale:

#!/bin/bash 
ip2dec() { 
    local a b c d [email protected] 
    IFS=. read -r a b c d <<< "$ip" 
    printf '%d\n' "$((a * 256 ** 3 + b * 256 ** 2 + c * 256 + d))" 
} 

ip2dec "[email protected]" 

Demo:

$ ./dec2ip 1113984275 
66.102.13.19 

$ ./ip2dec 66.102.13.19 
1113984275 

Questi due script si basano su caratteristiche Bash che non è presente in alcune shell derivate da Bourne. Qui ci sono le versioni di AWK da usare al posto:

#!/usr/bin/awk -f 
# dec2ip 
BEGIN { 
    dec = ARGV[1] 
    for (e = 3; e >= 0; e--) { 
     octet = int(dec/(256^e)) 
     dec -= octet * 256^e 
     ip = ip delim octet 
     delim = "." 
    } 
    printf("%s\n", ip) 
} 

e

#!/usr/bin/awk -f 
# ip2dec 
BEGIN { 
    ip = ARGV[1] 
    split(ip, octets, ".") 
    for (i = 1; i <= 4; i++) { 
     dec += octets[i] * 256 ** (4 - i) 
    } 
    printf("%i\n", dec) 
} 

Possono essere chiamati nello stesso modo come gli script Bash di cui sopra.

+0

Qual è il numero? –

+0

@AshBurlaczenko: il numero decimale per l'indirizzo IP specificato è 1113984275 –

+0

Grazie per la tua decisione, più chiaro, ho corretto l'errore. E come funziona l'operazione inversa? Da 1113984275 per ottenere 66.102.13.19. – KarlsD

7

indirizzo IP -> Numero: echo 66.102.13.19 | tr . '\n' | awk '{s = s*256 + $1} END{print s}' Number -> Indirizzo IP: (export ip=1113984275; for i in {1..4}; do s='.'$((ip%256))$s && ((ip>>=8)); done; echo ${s:1})

+0

È grandioso, ma come lo facciamo nell'altro modo. Ad es. Numero IP -> Indirizzo IP – bsmoo

+1

Ho aggiornato il metodo su come convertire il numero IP in indirizzo IP. :) –

+0

Puoi evitare la chiamata a 'tr' specificando il separatore di record, es .:' awk 'BEGIN {RS = "."} ... 'or' awk' {s = s * 256 + $ 1} END {print s} 'RS = .' – bufh

3

mia versione per int a IP di conversione:

echo 3232235521| awk {'print rshift(and($1, 0xFF000000), 24) "." rshift(and($1, 0x00FF0000), 16) "." rshift(and($1, 0x0000FF00), 8) "." and($1, 0x000000FF) '}

3

Ecco il mio prendere:

$ host google.com 
google.com has address 216.58.216.142 
$ ./ip2d.sh 216.58.216.142 
3627735182 
$ ./d2ip.sh 3627735182 
216.58.216.142 

ip2d.sh:

#!/bin/bash 

IFS=. 
set -- $* 
echo $((($1*256**3) + ($2*256**2) + ($3*256) + ($4))) 

d2ip.sh:

#!/bin/bash 

IFS=" " read -r a b c d <<< $(echo "obase=256 ; $1" |bc) 
echo ${a#0}.${b#0}.${c#0}.${d#0} 
+0

Love it. ip2d potrebbe essere una funzione (bash) come 'ip2d() {IFS =. eval 'set - $ 1'; echo ... 'e d2ip potrebbe anche essere scritto' IFS = \ read -rabcd <<(echo "obase = 256; $ 1" | bc) ' – bufh

+0

E ancora più breve:' A = ($ (dc -e "256o $ 1 p ")); IFS =. eval 'echo "$ {A [*] # 0}"' '(hanno lo stesso problema dell'originale quando un quad ha due primi 0). – bufh

1

Penso che ci sia una soluzione più semplice che gestisce anche un numero arbitrario di ottetti senza riferimenti a compensazioni fisse ecc

echo 66.102.13.19 | 
    tr . '\n' | 
    while read octet; do 
     printf "%.08d" $(echo "obase=2;$octet" | bc) 
    done | 
    echo $((2#$(cat))) 

uscita: 1.113.984,275 mila

+0

Ciao, ho una domanda sulla tua risposta. Puoi spiegare il significato di '$ ((2 # $ (cat)))' –

+1

@yundongxu Il comando 'cat' legge i dati inviati in input standard che è una stringa di cifre binarie. L'espressione '$ ((2 # ...))' converte "..." dalla base 2 al decimale. –

2

Lo spostamento binario è sempre più veloce di moltiplicare o dividere.
L'utilizzo di un binario AND è più veloce di mod.

ip2dec(){ # Convert an IPv4 IP number to its decimal equivalent. 
      declare -i a b c d; 
      IFS=. read a b c d <<<"$1"; 
      echo "$(((a<<24)+(b<<16)+(c<<8)+d))"; 
     } 
dec2ip(){ # Convert an IPv4 decimal IP value to an IPv4 IP. 
      declare -i a=$((~(-1<<8))) b=$1; 
      set -- "$((b>>24&a))" "$((b>>16&a))" "$((b>>8&a))" "$((b&a))"; 
      local IFS=.; 
      echo "$*"; 
     } 

ip=66.102.13.19 
a=$(ip2dec "$ip") 
b=$(dec2ip "$a") 
echo "$ip DecIP=$a IPv4=$b " 

Nota: Questo sistema non riuscirà con valori come 0008.
Bash pensa che sia un numero ottale.

Per risolvere questo, ogni valore dovrà essere pulita con qualcosa di simile:

IsDecInt()( # Is the value given on $1 a decimal integer (with sign)? 
       declare n=$1; set -- 
       if [[ $n =~ ^([+-]?)((0)|0*([0-9]*))$ ]]; then 
        set -- "${BASH_REMATCH[@]:1}" 
       else 
        exit 1 
       fi 
       echo "$1$3$4"; 
     ) 

    a=$(IsDecInt "$a")||{ Echo "Value $a is not an integer" >&2; exit 1; } 

Per (molto) vecchio shell: bash dal 2.04, o il trattino o qualsiasi shell (ragionevole):

ip2dec(){ # Convert an IPv4 IP number to its decimal equivalent. 
      local a b c d; 
      IFS=. read a b c d <<-_EOF_ 
$1 
_EOF_ 
      echo "$(((a<<24)+(b<<16)+(c<<8)+d))"; 
     } 

dec2ip(){ # Convert an IPv4 decimal IP value to an IPv4 IP. 
      local a=$((~(-1<<8))) b=$1; 
      set -- "$((b>>24&a))" "$((b>>16&a))" "$((b>>8&a))" "$((b&a))"; 
      local IFS=.; 
      echo "$*"; 
     } 

ip=$1 
a=$(ip2dec "$ip") 
b=$(dec2ip "$a") 
echo "$ip DecIP=$a IPv4=$b "