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), bash4.3 e versioni successive, busybox sh, yash, mkshe 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 $IPcontenga 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 $IPproviene da una fonte non attendibile, ciò equivarrebbe a una vulnerabilità nell'iniezione di comando.
Fondamentalmente, come stiamo sostituendo ogni .in $IPcon +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 valueperché 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. zshlo supporta con una sintassi diversa:
$ setopt extendedglob # for (#b)
$ echo ${IP/(#b)(*).(*).(*).(*)/$match[2]}'
96
bashsupporta 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 noglobper evitare brutte sorprese per valori di $IPlike 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' 1indirizzo 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 pingesempio 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 basho ksh93o zsh -o octalzeroeso 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
mkshusa 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' posixopzione per riconoscere le costanti ottali).
IFSperreadlì:IFS=. read -a ArrIP<<<"$IP"