No es lo más fácil , pero podrías hacer algo como:
$ 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
Eso debería funcionar en ksh93 (donde ese ${var//pattern/replacement}
operador viene), bash
4.3+, busybox sh
, yash
, mksh
y zsh
, aunque, por supuesto , en zsh
, existen métodos mucho más simples . En versiones anteriores de bash
, necesitaría eliminar las comillas internas. Funciona también con esas comillas internas eliminadas en la mayoría de los otros shells, pero no con ksh93.
Se supone que $IP
contiene una representación válida de cuatro decimales de una dirección IPv4 (aunque eso también funcionaría para representaciones de cuatro hexadecimales como 0x6d.0x60.0x4d.0xf
(e incluso octal en algunos shells) pero generaría los valores en decimal). Si el contenido $IP
proviene de una fuente no confiable, eso equivaldría a una vulnerabilidad de inyección de comando.
Básicamente, lo que estamos reemplazando cada .
en $IP
con +256*(
, terminamos la evaluación:
$(( (109+256*(96+256*(77+256*(15))))>> x &255 ))
Así que estamos construyendo un entero de 32 bits de los 4 bytes como una dirección IPv4 en última instancia es (aunque con los bytes invertidos) ¹ y luego usando los >>
, &
operadores bit a bit para extraer los bytes correspondientes.
Usamos el ${param+value}
operador estándar (aquí en el $-
que se garantiza que siempre se establecerá) en lugar de solo value
porque de lo contrario el analizador aritmético se quejaría de paréntesis no coincidentes. El shell aquí puede encontrar el cierre ))
para la apertura $((
, y luego realizar las expansiones en el interior que resultarán en la expresión aritmética para evaluar.
Con $(((${IP//./"+256*("}))))&255))
lugar, la carcasa podría tratar la segunda y tercera )
s allí como el cierre ))
para $((
y informar de un error de sintaxis.
En ksh93, también puedes hacer:
$ echo "${IP/@(*).@(*).@(*).@(*)/\2}"
96
bash
, mksh
, zsh
Han copiado de ksh93 ${var/pattern/replacement}
operador, pero no que la captura de grupos manipulación de la pieza. zsh
lo admite con una sintaxis diferente:
$ setopt extendedglob # for (#b)
$ echo ${IP/(#b)(*).(*).(*).(*)/$match[2]}'
96
bash
admite alguna forma de manejo de grupos de captura en su operador de coincidencia regexp , pero no en ${var/pattern/replacement}
.
POSIXY, usarías:
(IFS=.; set -o noglob; set -- $IP; printf '%s\n' "$2")
Para noglob
evitar sorpresas negativas para valores $IP
similares 10.*.*.*
, la subshell para limitar el alcance de esos cambios en las opciones y $IFS
.
¹ Una dirección IPv4 es solo un número entero de 32 bits y 127.0.0.1, por ejemplo, es solo una de las muchas representaciones textuales (aunque las más comunes). Esa misma dirección IPv4 típica de la interfaz de bucle invertido también se puede representar como 0x7f000001 o 127.1 (quizás una más apropiada aquí para decir que es la 1
dirección en la red 127.0 / 8 clase A), o 0177.0.1, o las otras combinaciones de 1 a 4 números expresados como octales, decimales o hexadecimales. Puede pasar todos esos, ping
por ejemplo, y verá que todos harán ping localhost.
Si no te importa el efecto secundario de establecer una variable temporal arbitraria (en este caso $n
), en bash
o ksh93
, o zsh -o octalzeroes
, o lksh -o posix
, simplemente puede convertir todas esas representaciones de nuevo a un número entero de 32 bits con:
$((n=32,(${IP//./"<<(n-=8))+("})))
Y luego extraiga todos los componentes con >>
/ &
combinaciones como arriba.
$ 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 enteros de 32 bits con signo para sus expresiones aritméticas, puede usar $((# n=32,...))
allí para forzar el uso de números de 32 bits sin signo (y la posix
opción para que reconozca constantes octales).
IFS
pararead
allí:IFS=. read -a ArrIP<<<"$IP"