Non il più semplice , ma potresti fare qualcosa del tipo:
$ IP=109.96.77.15
$ echo "$((${-+"(${IP//./"+256*("}))))"}&255))"
109
$ echo "$((${-+"(${IP//./"+256*("}))))"}>>8&255))"
96
$ echo "$((${-+"(${IP//./"+256*("}))))"}>>16&255))"
77
$ echo "$((${-+"(${IP//./"+256*("}))))"}>>24&255))"
15
Che dovrebbe funzionare in ksh93 (dove quel ${var//pattern/replacement}
operatore viene), bash
4.3 e versioni successive, busybox sh
, yash
, mksh
e zsh
, anche se naturalmente in zsh
, ci sono approcci molto più semplici . Nelle versioni precedenti di bash
, avresti bisogno di rimuovere le virgolette interne. Funziona con quelle citazioni interne rimosse anche nella maggior parte delle altre shell, ma non in ksh93.
Ciò presuppone che $IP
contenga una rappresentazione quad-decimale valida di un indirizzo IPv4 (sebbene funzionerebbe anche per rappresentazioni quad-esadecimali come 0x6d.0x60.0x4d.0xf
(e persino ottale in alcune shell) ma genererebbe i valori in decimali). Se il contenuto di $IP
proviene da una fonte non attendibile, ciò equivarrebbe a una vulnerabilità nell'iniezione di comando.
Fondamentalmente, come stiamo sostituendo ogni .
in $IP
con +256*(
, finiamo per valutare:
$(( (109+256*(96+256*(77+256*(15))))>> x &255 ))
Quindi stiamo costruendo un intero a 32 bit da quelle 4 byte come un indirizzo IPv4 in ultima analisi, è (anche se con i byte invertiti) ¹ e poi utilizzando i >>
, &
operatori bit per bit per estrarre i byte rilevanti.
Usiamo l' ${param+value}
operatore standard (qui su $-
cui è garantito che sia sempre impostato) anziché semplicemente value
perché altrimenti il parser aritmetico si lamenterebbe di parentesi non corrispondenti. Qui la shell può trovare la chiusura ))
per l'apertura $((
, quindi eseguire le espansioni all'interno che determineranno l'espressione aritmetica da valutare.
Con $(((${IP//./"+256*("}))))&255))
invece, il guscio tratterebbe, secondo e terzo )
s lì come la chiusura ))
per $((
e riportare un errore di sintassi.
In ksh93, puoi anche fare:
$ echo "${IP/@(*).@(*).@(*).@(*)/\2}"
96
bash
, mksh
, zsh
Hanno copiato di ksh93 ${var/pattern/replacement}
operatore, ma non che la cattura-gruppo di movimentazione e sollevamento. zsh
lo supporta con una sintassi diversa:
$ setopt extendedglob # for (#b)
$ echo ${IP/(#b)(*).(*).(*).(*)/$match[2]}'
96
bash
supporta una qualche forma di gestione dei gruppi di acquisizione nel suo operatore di regexp matching , ma non in ${var/pattern/replacement}
.
POSIXly, useresti:
(IFS=.; set -o noglob; set -- $IP; printf '%s\n' "$2")
Il noglob
per evitare brutte sorprese per valori di $IP
like 10.*.*.*
, la subshell per limitare l'ambito di tali modifiche alle opzioni e $IFS
.
¹ Un indirizzo IPv4 è solo un numero intero a 32 bit e, ad esempio, 127.0.0.1 è solo una delle molte (anche se le più comuni) rappresentazioni testuali. Lo stesso tipico indirizzo IPv4 dell'interfaccia di loopback può anche essere rappresentato come 0x7f000001 o 127.1 (forse uno più appropriato qui per dire che è l' 1
indirizzo sulla rete di classe A 127.0 / 8), o 0177.0.1, o le altre combinazioni di 1 a 4 numeri espressi come ottali, decimali o esadecimali. Puoi passare tutti quelli ad ping
esempio e vedrai che eseguiranno il ping di localhost.
Se non ti interessa l'effetto collaterale dell'impostazione di una variabile temporanea arbitraria (qui $n
), in bash
o ksh93
o zsh -o octalzeroes
o lksh -o posix
, puoi semplicemente riconvertire tutte quelle rappresentazioni in un numero intero a 32 bit con:
$((n=32,(${IP//./"<<(n-=8))+("})))
E quindi estrarre tutti i componenti con >>
/ &
combinazioni come sopra.
$ IP=0x7f000001
$ echo "$((n=32,(${IP//./"<<(n-=8))+("})))"
2130706433
$ IP=127.1
$ echo "$((n=32,(${IP//./"<<(n-=8))+("})))"
2130706433
$ echo "$((n=32,((${IP//./"<<(n-=8))+("}))>>24&255))"
127
$ perl -MSocket -le 'print unpack("L>", inet_aton("127.0.0.1"))'
2130706433
mksh
usa numeri interi a 32 bit con segno per le sue espressioni aritmetiche, puoi usarlo $((# n=32,...))
per forzare l'uso di numeri a 32 bit senza segno (e l' posix
opzione per riconoscere le costanti ottali).
IFS
perread
lì:IFS=. read -a ArrIP<<<"$IP"