Pas le plus simple , mais vous pourriez faire quelque chose comme:
$ 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
Cela devrait fonctionner dans ksh93 (où que l' ${var//pattern/replacement}
opérateur vient), bash
4.3 +, busybox sh
, yash
, mksh
et zsh
, même si bien sûr dans zsh
, il y a des approches beaucoup plus simples . Dans les anciennes versions de bash
, vous devez supprimer les guillemets internes. Cela fonctionne avec ces guillemets internes supprimés dans la plupart des autres shells, mais pas ksh93.
Cela suppose qu'il $IP
contient une représentation quadri-décimale valide d'une adresse IPv4 (bien que cela fonctionnerait également pour des représentations quad-hexadécimales comme 0x6d.0x60.0x4d.0xf
(et même octal dans certains shells) mais produirait les valeurs en décimal). Si le contenu de $IP
provient d'une source non fiable, cela équivaudrait à une vulnérabilité d'injection de commande.
Au fond, comme nous remplaçons tous .
dans $IP
avec +256*(
, on finit par évaluer:
$(( (109+256*(96+256*(77+256*(15))))>> x &255 ))
Nous sommes donc construire un entier de 32 bits sur ces 4 octets comme une adresse IPv4 est en fin de compte (mais avec les octets inversés) ¹, puis en utilisant les >>
, &
opérateurs de bits pour extraire les octets pertinents.
Nous utilisons l' ${param+value}
opérateur standard (ici sur $-
lequel il est garanti d'être toujours défini) au lieu de simplement value
parce que sinon l'analyseur arithmétique se plaindrait de parenthèses incompatibles. Le shell ici peut trouver la fermeture ))
de l'ouverture $((
, puis effectuer les extensions à l'intérieur qui entraîneront l'expression arithmétique à évaluer.
Avec à la $(((${IP//./"+256*("}))))&255))
place, le shell traiterait le deuxième et le troisième )
s comme la fermeture ))
de $((
et rapporterait une erreur de syntaxe.
Dans ksh93, vous pouvez également faire:
$ echo "${IP/@(*).@(*).@(*).@(*)/\2}"
96
bash
, mksh
, zsh
Ont copié de ksh93 ${var/pattern/replacement}
opérateur , mais pas cette partie de manutention capture groupe. zsh
le prend en charge avec une syntaxe différente:
$ setopt extendedglob # for (#b)
$ echo ${IP/(#b)(*).(*).(*).(*)/$match[2]}'
96
bash
prend en charge une certaine forme de gestion de groupe de capture dans son opérateur de correspondance d'expressions régulières , mais pas dans ${var/pattern/replacement}
.
POSIXly, vous utiliseriez:
(IFS=.; set -o noglob; set -- $IP; printf '%s\n' "$2")
Le noglob
pour éviter les mauvaises surprises pour les valeurs de $IP
like 10.*.*.*
, le sous-shell pour limiter la portée de ces changements d'options et $IFS
.
¹ Une adresse IPv4 n'est qu'un entier de 32 bits et 127.0.0.1, par exemple, n'est qu'une des nombreuses représentations textuelles (bien que les plus courantes). Cette même adresse IPv4 typique de l'interface de bouclage peut également être représentée comme 0x7f000001 ou 127.1 (peut-être une plus appropriée ici pour dire que c'est l' 1
adresse sur le réseau 127.0 / 8 classe A), ou 0177.0.1, ou les autres combinaisons de 1 à 4 nombres exprimés en octal, décimal ou hexadécimal. Vous pouvez passer tous ceux-ci à, ping
par exemple, et vous verrez qu'ils cingleront tous localhost.
Si cela ne vous dérange pas l'effet secondaire de la définition d'une variable temporaire arbitraire (ici $n
), dans bash
ou ksh93
ou zsh -o octalzeroes
ou lksh -o posix
, vous pouvez simplement reconvertir toutes ces représentations en un entier 32 bits avec:
$((n=32,(${IP//./"<<(n-=8))+("})))
Et puis extrayez tous les composants avec >>
/ &
combinaisons comme ci-dessus.
$ 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
utilise des entiers 32 bits signés pour ses expressions arithmétiques, vous pouvez l'utiliser $((# n=32,...))
pour forcer l'utilisation de nombres 32 bits non signés (et l' posix
option pour qu'il reconnaisse les constantes octales).
IFS
pour leread
là:IFS=. read -a ArrIP<<<"$IP"