Como gerar um endereço MAC aleatório válido com shell bash


16

Como posso gerar um endereço mac aleatório válido com bash.

A primeira metade do endereço deve sempre permanecer a mesma assim

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

apenas o valor x deve ser gerado aleatoriamente?


10
echo -n 00-60-2F; dd bs=1 count=3 if=/dev/random 2>/dev/null |hexdump -v -e '/1 "-%02X"'
precisa saber é

1
@artistoex Isso foi lindo ... Por que você não postou isso como resposta?
bobmagoo

Respostas:


18

Aqui está um peixe.

Este script de shell irá gerar a sequência aleatória que você procura:

#!/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

Eu tinha apenas algo aqui que mostrava como executá-lo a partir da linha de comando, mas depois de olhar para a solução complicada (mas votada) de Dennis Williamson, vejo que a resposta que as pessoas esperam é aquela em que não precisam fazer nenhum trabalho si mesmos.


obrigado por perceber que eu estava tentando fazê-lo aprender a pescar em vez de dar uma solução para uma colher
RobotHumans

1
Você sempre pode explicar a sua resposta para que vocês dois estão ensinando-o a pescar, além de fornecer um desta vez ...
Jed Daniels

Esse script roda consideravelmente muito mais rápido que o proposto por hbdgaf e não gera nenhum endereço MAC inválido em um loop de 1000 vezes. Obrigado!
de Bruno Dedo

1
Sua solução funciona e possui apenas 3 linhas. Eu estou vendido.
Richard Gomes

17
  1. Gere um int de tamanho apropriado da seguinte maneira: http://tldp.org/LDP/abs/html/randomvar.html
  2. Converta em hexadecimal da seguinte forma: http://snipplr.com/view/2428/convert-from-int-to-hex/
  3. Adicione os traços entre três pedaços gerados 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

Ou em 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'))

Observe que a versão python usa apenas um campo amplo de 16 para gerar um caractere hexadecimal, portanto você não precisa se preocupar com o preenchimento zero - abordagem alterada para abordar um comentário.


+1 extra se você fornecer um exemplo de cada um (eu sei que você o está ensinando a pescar, mas você pode dar a ele as peças do quebra-cabeça para montar e explicar como / por que elas funcionam).
precisa

@ Dani Daniels - feito e feito. código fornecido.
RobotHumans

Este código está gerando alguns MACs inválidos para mim. Enrolando-1000 vezes eu tenho alguns MACs como 00-60-2F-8B-5-2C, 00-60-2F-A-71-97, 00-60-2F-82-F1-4.
de Bruno Dedo

Foi apenas algo que joguei lá fora, já que o OP estava insistindo no bash. Você está dizendo que não consegue descobrir como preencher os dígitos com zero, certo? @BrunoFinger
RobotHumans 22/03

Pode ser facilmente reformulado para usar 16 em vez de 255 e gerar o espaço reservado zero. É apenas mais linhas ...
RobotHumans 22/03

16

No passado, eu fiz isso usando:

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

mas isso só os fará no intervalo de 0 a 9. Para meus propósitos, isso foi bom o suficiente.

Provavelmente, uma solução melhor seria usar printf:

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

Veja como isso funciona:

  • O programa printf é baseado na função C "printf", que utiliza uma "string de formato" como o primeiro parâmetro e, em seguida, parâmetros adicionais preenchem a string de formato.
  • % na cadeia de formato introduz um "especificador de formato" que pode ser um ou mais caracteres informando como formatar os argumentos.
  • Um zero inicial (0) em um especificador de formato significa que a saída numérica resultante deve ser preenchida com zeros iniciais até a largura especificada.
  • O 2 diz que o especificador deve ser exibido com dois caracteres de largura.
  • O X termina o especificador e indica que ele deve ser interpretado como um número e exibido como hexidecimal. Por estar em maiúscula, as letras af devem estar em maiúsculas.
  • O \ n é uma nova linha - printf interpreta a barra invertida como um código de escape que pode ser usado para exibir outros caracteres, geralmente caracteres complicados como a nova linha.
  • Os caracteres restantes no especificador de formato são impressos literalmente, incluindo o "00-06-2F-" inicial e os traços entre os especificadores de formato.
  • Os argumentos restantes são substituições de variáveis ​​de shell (indicadas por $) e incluem uma expressão matemática que é um número aleatório (RANDOM) módulo 256. Isso resulta em um número aleatório entre 0 e 255.

2
Como user58033 corretamente apontou em uma resposta (que pode ter desaparecido agora): %02Xdaria uma letra maiúscula.
quer

Ah, bom argumento. Aumentei que a pergunta original deu um exemplo usando maiúsculas. Obrigado pelo bem-vindo. :-)
Sean Reifschneider

+1 extra se você puder explicar o que está acontecendo e por que sua solução funciona.
precisa

Lá vai você, @Jed.
Sean Reifschneider 07/07

12

Usando ferramentas padrão,

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

ou

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

pode ser o mais curto de todos.


Você pode descrever em sua resposta o que od faz exatamente? Ajudaria a usá-lo de outras maneiras também!
Bruno Bieri 12/10

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"

As chaves para a maneira como isso funciona:

  • LC_CTYPE=C - permite caracteres> 0x7F
  • IFS=- desativa a interpretação de \t(tab), \n(nova linha) e espaço
  • -d ''- permite novas linhas
  • -rpermite \(e quase sempre deve ser usado por hábito read)
  • O especificador de formato -%02x\n faz com que a saída seja um hífen literal seguido por um número hexadecimal de dois dígitos, incluindo um zero à esquerda, se apropriado. A nova linha é supérflua aqui e pode ser omitida.
  • A readrecebe um único byte ( -n 1) a partir /dev/urandomda escala de 0 a 255 ( 00a FF).
  • A citação simples no último argumento para o printfloop faz com que o caractere seja exibido como seu valor numérico ("A" é exibido como "65"). Veja a especificação POSIX paraprintf onde diz:

    Se o caractere principal for uma aspas simples ou aspas duplas, o valor será o valor numérico no conjunto de códigos subjacente do caractere após a aspas simples ou aspas simples.


Parece que a necessidade IFS= read …de evitar dobrar 09 0a e 20 (os caracteres IFS usuais) em 00.
Chris Johnsen

@ Chris: Desculpe, tirei algumas coisas enquanto checava duas vezes e esqueci de colocá-las de volta. Também precisa -d ''. Eu vou consertar minha resposta. Obrigado por me avisar.
Pausado até novo aviso.

Ops, o -rque protege `\` caiu. Desejo que o tratamento adequado de dados binários em programas shell não seja tão complicado. Impossible Parece impossível representar com precisão 00 no meio da string. Seu método de caractere único por vez lida com 00 em virtude da cooperação conveniente (projetada?) Entre a readinterpolação de cadeias e como printftrata o argumento de um caractere '. Suspiro.
Chris Johnsen

@ Chris: Eu gostaria que meu processador DWIM não estivesse no fritz. A propósito, você pode estar interessado em ver um script Bash puro que escrevi que duplica a funcionalidade principal do hexdump -C.
Pausado até novo aviso.

+1 extra se você puder explicar o que está acontecendo e por que sua solução funciona.
precisa

7

A maneira mais curta que eu pude pensar foi usando o hexdump diretamente

echo 00-60-2f$(hexdump -n3 -e '/1 "-%02X"' /dev/random)
  • -n3 diz ao hexdump para ler três bytes
  • A string de formato imprime um traço e um valor hexadecimal de dois dígitos para cada byte
    • '/ 1' significa aplicar formato a cada byte lido
    • "-% 02X" é uma especificação printf para imprimir um valor hexadecimal inicial de zero, dois dígitos e maiúsculas
  • / dev / random é uma fonte de bytes aleatórios

Testado no GNU / Linux


Eficácia Unix no trabalho :-)
artistoex

hexdump -n3 -e'/3 "00-60-2F" 3/1 "-%02X"' /dev/randomé um pouco mais curto :-)
artistoex

4

Outra solução de uma linha

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

Mesma coisa em maiúsculas

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

Gere-o para uma variável de ambiente Bash

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

Detalhes:

  • od (despejo octal)

    -AnSuprime a representação do endereço principal (ruído extra) da saída.
    -N3Limite a saída para três bytes.
    -t xCSaída em hexadecimal, estilo de caractere ASCII, conforme desejado.
    /dev/urandomPseudo-arquivo de número aleatório do kernel do Linux.

  • sed (editor de fluxo) Para espaço para hífen em substituição.

    -e <SCRIPT> execute o script sed.

  • tr (tradução de string) Opcional, neste exemplo. Eu gosto de endereços MAC em maiúsculas nos meus scripts / ambiente.


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

2

Isso deve funcionar

echo 00-60-2f-`openssl rand -hex 3 | sed 's/\(..\)/\1-/g; s/.$//'`

0
end=$( echo $RANDOM | openssl md5 | sed 's/\(..\)/\1-/g' | cut -b-8 )
echo 00-60-2f-$end

5
+1 extra se você puder explicar o que está acontecendo e por que sua solução funciona.
precisa

0

Este também funciona. A saída está em letras maiúsculas, conforme necessário.

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

0

Isso funciona no #!/bin/shscript shell ( ) clássico :

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

Ou, se você deseja ter um prefixo 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
}

Exemplo 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

0

Outra opção é usar jot:

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

-w muda o formato, -s altera o separador e -rgera números aleatórios.

Os comandos usados odnas respostas postadas por artistoex e zero2cx adicionam traços extras à saída com OS X od, mas isso não:

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

OS X od( /usr/bin/odabaixo) usa um formato de saída diferente do GNU od:

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

$ god -N3 -tx1 -An /dev/random|tr ' ' -
-94-9e-5c

1
Cuidado com o jot. Eu tenho alguns mac gerado desta maneira que tem "100" neles, por exemplo 00-60-2F-100-A3-F6 ...
Petrus

@ Peter Você está certo, eu editei a resposta para mudar jot -w%02X -s- -r 3 1 256para jot -w%02X -s- -r 3 0 256.
Nisetama 7/12

0

No Linux:

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

Explicação:

No Linux, /proc/sys/kernel/random/uuidretorna um novo UUID do tipo 4 (aleatório) toda vez que você o lê. A maioria de seus caracteres é (pseudo) dígitos hexadecimais aleatórios, portanto, podemos usá-los. Por exemplo:

$ 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

Agora basta imprimir 00-60-2f-(sem nova linha) primeiro:

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

Prós:

  • dígitos hexadecimais desde o início, sem necessidade de conversão / filtragem;
  • printfe cutsão ferramentas POSIX;
  • (para o seu caso específico) hífens já em UUID, nós os usamos.

Contras:

  • precisamos nos lembrar dos dois dígitos não aleatórios no UUID;
  • /proc/sys/kernel/random/uuid pode não estar disponível em alguns sistemas;
  • somente letras minúsculas são tão fáceis (você precisa de uma etapa adicional para obter letras maiúsculas).

0

Um forro (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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.