Cómo generar una dirección MAC aleatoria válida con bash shell

16

¿Cómo puedo generar una dirección de mac aleatoria válida con bash?

La primera mitad de la dirección siempre debe permanecer igual así

00-60-2F-xx-xx-xx

solo el valor x debe generarse al azar?

NES
fuente
10
echo -n 00-60-2F; dd bs=1 count=3 if=/dev/random 2>/dev/null |hexdump -v -e '/1 "-%02X"'
artistoex
1
@artistoex Eso fue hermoso ... ¿Por qué no publicaste eso como respuesta?
bobmagoo

Respuestas:

18

Aquí hay un pez.

Este script de shell generará la cadena aleatoria que busca:

#!/bin/bash
hexchars="0123456789ABCDEF"
end=$( for i in {1..6} ; do echo -n ${hexchars:$(( $RANDOM % 16 )):1} ; done | sed -e 's/\(..\)/-\1/g' )
echo 00-60-2F$end

Acabo de tener algo aquí que mostró cómo ejecutarlo desde la línea de comandos, pero después de mirar a Dennis Williamson una solución enrevesada (pero votada) veo que la respuesta que la gente espera es aquella en la que no tienen que hacer ningún trabajo sí mismos.

deltaray
fuente
gracias por darme cuenta de que estaba tratando de hacer que aprendiera a pescar en lugar de
darle
1
Siempre podría explicar su respuesta para que ambos le estén enseñando cómo pescar, además de proporcionarle esta vez ...
Jed Daniels
Este script se ejecuta considerablemente mucho más rápido que el propuesto por hbdgaf y no genera ninguna dirección MAC no válida en un bucle de 1000 veces. ¡Gracias!
Bruno Finger
1
Su solución funciona y tiene solo 3 líneas. Estoy vendido.
Richard Gomes el
17

En el pasado hice esto usando:

echo 00-60-2F-$[RANDOM%10]$[RANDOM%10]-$[RANDOM%10]$[RANDOM%10]-$[RANDOM%10]$[RANDOM%10]

pero eso solo los hará en el rango 0-9. Para mis propósitos, eso fue lo suficientemente bueno.

Probablemente una mejor solución sería usar printf:

printf '00-60-2F-%02X-%02X-%02X\n' $[RANDOM%256] $[RANDOM%256] $[RANDOM%256]

Así es como funciona:

  • El programa printf se basa en la función C "printf", que toma una "cadena de formato" como primer parámetro y luego los parámetros adicionales completan la cadena de formato.
  • El% en la cadena de formato introduce un "especificador de formato" que puede tener uno o más caracteres que indican cómo formatear los argumentos.
  • Un cero inicial (0) en un especificador de formato significa que la salida numérica resultante debe rellenarse con ceros iniciales hasta el ancho especificado.
  • El 2 dice que el especificador debe mostrarse ocupando dos caracteres de ancho.
  • La X finaliza el especificador y denota que debe interpretarse como un número y mostrarse como hexadecimal. Como es mayúscula, las letras af deben ser mayúsculas.
  • El \ n es una nueva línea: printf interpreta la barra diagonal inversa como un código de escape que se puede usar para mostrar otros caracteres, a menudo caracteres complicados como la nueva línea.
  • Los caracteres restantes en el especificador de formato se imprimen literalmente, esto incluye el "00-06-2F-" inicial y los guiones entre los especificadores de formato.
  • Los argumentos restantes son sustituciones de variables de shell (denotadas por $) e incluyen una expresión matemática que es un número aleatorio (RANDOM) módulo 256. Esto da como resultado un número aleatorio entre 0 y 255.
Sean Reifschneider
fuente
2
Como user58033 señaló correctamente en una respuesta (que podría haber desaparecido ahora): %02Xdaría una letra mayúscula.
Arjan
Ah, buen punto. Espacié que la pregunta original dio un ejemplo usando mayúsculas. Gracias por la bienvenida :-)
Sean Reifschneider
Extra +1 si puede explicar lo que está sucediendo y por qué funciona su solución.
Jed Daniels
Ahí tienes, @Jed.
Sean Reifschneider
17
  1. Genere un int de tamaño apropiado como este: http://tldp.org/LDP/abs/html/randomvar.html
  2. Convierta a hexadecimal de la siguiente manera: http://snipplr.com/view/2428/convert-from-int-to-hex/
  3. Agregue los guiones entre tres fragmentos generados aleatoriamente
#!/bin/bash
RANGE=255
#set integer ceiling

number=$RANDOM
numbera=$RANDOM
numberb=$RANDOM
#generate random numbers

let "number %= $RANGE"
let "numbera %= $RANGE"
let "numberb %= $RANGE"
#ensure they are less than ceiling

octets='00-60-2F'
#set mac stem

octeta=`echo "obase=16;$number" | bc`
octetb=`echo "obase=16;$numbera" | bc`
octetc=`echo "obase=16;$numberb" | bc`
#use a command line tool to change int to hex(bc is pretty standard)
#they're not really octets.  just sections.

macadd="${octets}-${octeta}-${octetb}-${octetc}"
#concatenate values and add dashes

echo $macadd
#echo result to screen
#note: does not generate a leading zero on single character sections.  easily remediedm but that's an exercise for you

O en python:

from random import randint
def gen_mac_char():
  return hex((randint(0,16))).split('x')[1]
def gen_mac_pair():
  return ''.join([gen_mac_char(), gen_mac_char()])
def gen_last_half_mac(stem):
  return '-'.join([stem, gen_mac_pair(), gen_mac_pair(), gen_mac_pair()])
print(gen_last_half_mac('00-60-2F'))

Tenga en cuenta que la versión de Python solo usa un campo de 16 de ancho para generar un carácter hexadecimal, por lo que no tiene que preocuparse por el relleno cero: enfoque modificado para abordar un comentario.

RobotHumanos
fuente
Extra +1 si proporciona un ejemplo de cada uno (sé que le está enseñando a pescar, pero podría darle las piezas del rompecabezas para armar y explicar cómo / por qué funcionan).
Jed Daniels
@Jed Daniels - hecho y hecho. código proporcionado
RobotHumans
Este código está generando algunos MAC inválidos para mí. Enrollarlo 1000 veces llegué unos MAC como 00-60-2F-8B-5-2C, 00-60-2F-A-71-97, 00-60-2F-82-F1-4.
Bruno Finger
Fue algo que lancé allí ya que el OP insistía en bash. ¿Estás diciendo que no sabes cómo rellenar los dígitos individuales con un cero, verdad? @BrunoFinger
RobotHumans
Podría modificarse fácilmente para usar 16 en lugar de 255 y generar el marcador de posición cero. Son solo más líneas ...
RobotHumans
12

Usando herramientas estándar, ya sea

# output in capitals
hexdump -n3 -e'/3 "00-60-2F" 3/1 "-%02X"' /dev/random

o

# output in lower case letters
echo 00-60-2f$(od -txC -An -N3 /dev/random|tr \  -)

podría ser el más corto de todos.

artistoex
fuente
¿Puedes describir en tu respuesta qué hace exactamente od? ¡Sería útil usarlo de otras maneras también!
Bruno Bieri
7
#!/bin/bash
LC_CTYPE=C
MAC=00-60-2F
for i in {1..3}
do
    IFS= read -d '' -r -n 1 char < /dev/urandom
    MAC+=$(printf -- '-%02x\n' "'$char")
done
printf '%s\n' "$MAC"

Las claves de la forma en que esto funciona:

  • LC_CTYPE=C - permite caracteres> 0x7F
  • IFS=- desactiva la interpretación de \t(tab), \n(nueva línea) y espacio
  • -d ''- permite nuevas líneas
  • -rpermite \(y casi siempre debe usarse por hábito con read)
  • El especificador de formato -%02x\nhace que la salida sea un guión literal seguido de un número hexadecimal de dos dígitos que incluye un cero inicial, si corresponde. La nueva línea es superflua aquí y podría omitirse.
  • El readconsigue un solo byte ( -n 1) a partir de /dev/urandomen el rango de 0 a 255 ( 00a FF).
  • La comilla simple en el último argumento printfen el bucle hace que el carácter se muestre como su valor numérico ("A" se muestra como "65"). Consulte la especificación POSIX para saberprintf dónde dice:

    Si el carácter inicial es una comilla simple o una comilla doble, el valor será el valor numérico en el conjunto de códigos subyacente del carácter que sigue a la comilla simple o la comilla doble.

Pausado hasta nuevo aviso.
fuente
Parece que debe IFS= read …evitarse doblar 09 0a y 20 (los caracteres IFS habituales) en 00.
Chris Johnsen
@ Chris: Lo siento, saqué un par de cosas mientras hacía una doble verificación y olvidé volver a ponerlas. También es necesario -d ''. Arreglaré mi respuesta. Gracias por hacérmelo saber.
Pausado hasta nuevo aviso.
Vaya, se -rcayó el que protege `\`. Desearía que el manejo adecuado de los datos binarios en los programas de shell no fuera tan complicado. ☺ Parece imposible representar con precisión 00 en el medio de la cadena. Su método de un solo carácter a la vez maneja 00 en virtud de la cooperación conveniente (¿diseñada?) Entre la readinterpolación de cadenas y cómo printftrata el argumento de un carácter '. Suspiro.
Chris Johnsen
@ Chris: Desearía que mi procesador DWIM no estuviera en problemas. Por cierto, puede que te interese ver un script Bash puro que escribí que duplica la funcionalidad principal de hexdump -C.
Pausado hasta nuevo aviso.
Extra +1 si puede explicar lo que está sucediendo y por qué funciona su solución.
Jed Daniels
7

La forma más corta que pude encontrar fue usando hexdump directamente

echo 00-60-2f$(hexdump -n3 -e '/1 "-%02X"' /dev/random)
  • -n3 le dice a hexdump que lea tres bytes
  • La cadena de formato imprime un guión y un valor hexadecimal de dos dígitos para cada byte
    • '/ 1' significa aplicar formato para cada byte leído
    • "-% 02X" es una especificación printf para imprimir un valor hexadecimal mayúscula inicial de dos dígitos y cero
  • / dev / random es una fuente de bytes aleatorios

Probado en GNU / Linux

maxthoursie
fuente
Eficacia de Unix en el trabajo :-)
artistoex
hexdump -n3 -e'/3 "00-60-2F" 3/1 "-%02X"' /dev/randomes un poco más corto :-)
artistoex
4

Otra solución de una línea

$ echo '00 60 2f'$(od -An -N3 -t xC /dev/urandom) | sed -e 's/ /-/g'

Lo mismo en mayúsculas

$ echo '00 60 2f'$(od -An -N3 -t xC /dev/urandom) | sed -e 's/ /-/g' | tr '[:lower:]' '[:upper:]'

Generarlo para una variable de entorno Bash

$ export MAC=$(echo '00 60 2f'$(od -An -N3 -t xC /dev/urandom) | sed -e 's/ /-/g')
$ echo $MAC

Detalles:

  • od (volcado octal)

    -AnSuprime la representación de dirección principal (ruido adicional) de la salida.
    -N3Limite la salida a tres bytes.
    -t xCSalida en hexadecimal, estilo de caracteres ASCII, según se desee.
    /dev/urandomPseudoarchivo de números aleatorios del kernel de Linux.

  • sed (editor de flujo) Para la sustitución de espacios con guiones.

    -e <SCRIPT> ejecuta el script sed.

  • tr (traducción de cadena) Opcional, en este ejemplo. Me gustan las direcciones MAC mayúsculas en mis scripts / entorno.

zero2cx
fuente
2
#!/bin/bash
#Creates an array containing all hexadecimal characters
HEX=(a b c d e f 0 1 2 3 4 5 6 7 8 9)
#Defines MAC string length as 0 (total SL will be 17)
SL=0
#Loop sequentially assigns random hex characters in pairs until a full
#MAC address is generated.
while [ $SL -lt 17 ]
do
        num=`shuf -i 0-15 -n 1` #Generates random number which will be used as array index
        RMAC="$RMAC""${HEX[$num]}" #Uses the randomly generated number to select a hex character
        num=`shuf -i 0-15 -n 1` #New random number
        RMAC="$RMAC""${HEX[$num]}" #Appends second hex character
        SL=$[`echo $RMAC | wc -c` - 1] #Calculates SL and stores in var SL
    if [ $SL -lt 17 ] #If string is uncomplete, appends : character
            then
            RMAC=""$RMAC":"
    fi
done
echo $RMAC #Displays randomly generated MAC address
Hematoma
fuente
2

Esto debería funcionar

echo 00-60-2f-`openssl rand -hex 3 | sed 's/\(..\)/\1-/g; s/.$//'`
linuxrules94
fuente
0
end=$( echo $RANDOM | openssl md5 | sed 's/\(..\)/\1-/g' | cut -b-8 )
echo 00-60-2f-$end
Kevin Duterne
fuente
55
Extra +1 si puede explicar lo que está sucediendo y por qué funciona su solución.
Jed Daniels
0

Este también funciona. La salida es todo en mayúsculas según sea necesario.

openssl rand -hex 3 | sed 's/\(..\)\(..\)\(..\)/00-60-2F-\1-\2-\3/' | tr [a-f] [A-F]
Jaroslav Kucera
fuente
0

Esto funciona en el #!/bin/shscript clásico de shell ( ):

random_mac() {
    printf '%.2x\n' "$(shuf -i 0-281474976710655 -n 1)" | sed -r 's/(..)/\1:/g' | cut -d: -f -6
}

O, si quieres tener un prefijo personalizado:

random_mac_with_prefix() {
    echo -n "00:60:2f:" &&
    printf '%.2x\n' "$(shuf -i 0-281474976710655 -n 1)" | sed -r 's/(..)/\1:/g' | cut -d: -f -3
}

Ejemplo de uso:

$ random_mac
96:ef:45:28:45:25
$ random_mac
7e:47:26:ae:ab:d4
$ random_mac_with_prefix 
00:60:2f:24:f4:18
$ random_mac_with_prefix 
00:60:2f:63:08:b2
kvaps
fuente
0

Otra opción es usar jot:

echo 00-60-2F-$(jot -w%02X -s- -r 3 0 256)

-wcambia el formato, -scambia el separador y -rgenera números aleatorios.

Los comandos que se utilizan oden las respuestas publicadas por artistoex y zero2cx agregan guiones adicionales a la salida con OS X od, pero esto no:

echo 00-60-2f-$(od -tx1 -An -N3 /dev/random|awk '$1=$1'|tr \  -)

OS X od( /usr/bin/odabajo) usa un formato de salida diferente al de GNU od:

$ /usr/bin/od -N3 -tx1 -An /dev/random|tr ' ' -
-----------c7--fd--55----------------------------------------------------

$ god -N3 -tx1 -An /dev/random|tr ' ' -
-94-9e-5c
nisetama
fuente
1
Cuidado con jot. Tengo algunos mac generados de esta manera que tienen "100" en ellos, por ejemplo, 00-60-2F-100-A3-F6 ...
petrus
@petrus Tienes razón, he editado la respuesta al cambio jot -w%02X -s- -r 3 1 256a jot -w%02X -s- -r 3 0 256.
nisetama
0

En Linux:

printf '00-60-2f-' && cut -b 7-11,24-26 /proc/sys/kernel/random/uuid

Explicación:

En Linux /proc/sys/kernel/random/uuiddevuelve un nuevo UUID de tipo 4 (aleatorio) cada vez que lo lee. La mayoría de sus caracteres son dígitos hexadecimales (pseudo) aleatorios, por lo que podemos usarlos. P.ej:

$ cat /proc/sys/kernel/random/uuid
5501ab12-b530-4db5-a8ea-3df93043f172
$ #           ^    ^       Beware, these characters are not random.
$ #   ^^^^^            ^^^ Let's use characters on these positions.
$ cut -b 7-11,24-26 /proc/sys/kernel/random/uuid
6d-74-a1
$ cut -b 7-11,24-26 /proc/sys/kernel/random/uuid
13-f9-75

Ahora es suficiente imprimir 00-60-2f-(sin nueva línea) primero:

$ printf '00-60-2f-' && cut -b 7-11,24-26 /proc/sys/kernel/random/uuid
00-60-2f-86-f9-21

Pros:

  • dígitos hexadecimales desde el principio, no se necesita conversión / filtrado;
  • printfy cutson herramientas POSIX;
  • (para su caso específico) guiones que ya están en UUID, los usamos.

Contras:

  • debemos tener en cuenta los dos dígitos no aleatorios en UUID;
  • /proc/sys/kernel/random/uuid puede no estar disponible en algunos sistemas;
  • solo las letras minúsculas son tan fáciles (necesita un paso adicional para obtener letras mayúsculas).
Kamil Maciorowski
fuente
0

Un trazador de líneas (bash)

mac=$(c=0;until [ $c -eq "6" ];do printf ":%02X" $(( $RANDOM % 256 ));let c=c+1;done|sed s/://)

resultado

$ echo $mac
93:72:71:0B:9E:89
Zibri
fuente