How can i generate a valid random mac adress with bash.
The first half of the adress should always stay same like this
00-60-2F-xx-xx-xx
just the x value should be generated random?
In the past I've done this using:
echo 00-60-2F-$[RANDOM%10]$[RANDOM%10]-$[RANDOM%10]$[RANDOM%10]-$[RANDOM%10]$[RANDOM%10]
but that will only make them in the range 0-9. For my purposes, that was good enough.
Probably a better solution would be to use printf:
printf '00-60-2F-%02X-%02X-%02X\n' $[RANDOM%256] $[RANDOM%256] $[RANDOM%256]
Here's how that works:
Here is a fish.
This shell script will generate the random string you seek:
#!/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
I did just have something here that showed how to run it from the command line, but after looking at Dennis Williamson convoluted (but upvoted) solution I see that the answer that people expect is the one where they don't have to do any work themselves.
#!/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
Or in 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'))
Note that the python version only uses a 16 wide field to generate a hex char, so you don't have to worry about zero padding - approach amended to address a comment.
00-60-2F-8B-5-2C
, 00-60-2F-A-71-97
, 00-60-2F-82-F1-4
.
Mar 21, 2015 at 20:49
Using standard tools, either
# output in capitals
hexdump -n3 -e'/3 "00-60-2F" 3/1 "-%02X"' /dev/random
or
# output in lower case letters
echo 00-60-2f$(od -txC -An -N3 /dev/random|tr \ -)
might be the shortest of all.
#!/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"
The keys to the way this works:
LC_CTYPE=C
- allows characters > 0x7F
IFS=
- disables interpretation of \t
(tab), \n
(newline) and space
-d ''
- allows newlines
-r
allows \
(and should almost always be used by habit with read
)
The format specifier -%02x\n
causes the output to be a literal hyphen followed by a two-digit hexadecimal number including a leading zero, if appropriate. The newline is superfluous here and could be omitted.
The read
gets a single byte (-n 1
) from /dev/urandom
in the range 0 to 255 (00
to FF
).
The single quote in the last argument to the printf
in the loop causes the character to be output as its numeric value ("A" is output as "65"). See the POSIX specification for printf
where it says:
If the leading character is a single-quote or double-quote, the value shall be the numeric value in the underlying codeset of the character following the single-quote or double-quote.
IFS= read …
to avoid folding 09 0a and 20 (the usual IFS chars) into 00.
Dec 4, 2010 at 20:37
-d ''
. I'll fix my answer. Thanks for letting me know.
Dec 4, 2010 at 20:48
-r
that protects ` \ ` fell out. I wish proper handling of binary data in shell programs was not so fiddly. ☺ It seems impossible to accurately represent 00 in the middle of the string. Your single-character-at-a-time method handles 00 by virtue of convenient (designed?) cooperation between read
, string interpolation and how printf
treats the one-character argument '
. Sigh.
Dec 4, 2010 at 21:21
hexdump -C
.
Dec 4, 2010 at 21:58
The shortest way I could come up with was using hexdump directly
echo 00-60-2f$(hexdump -n3 -e '/1 "-%02X"' /dev/random)
Tested on GNU/Linux
hexdump -n3 -e'/3 "00-60-2F" 3/1 "-%02X"' /dev/random
is a little shorter :-)
Another one line solution
$ echo '00 60 2f'$(od -An -N3 -t xC /dev/urandom) | sed -e 's/ /-/g'
Same thing in upper case
$ echo '00 60 2f'$(od -An -N3 -t xC /dev/urandom) | sed -e 's/ /-/g' | tr '[:lower:]' '[:upper:]'
Generate it for a Bash environment variable
$ export MAC=$(echo '00 60 2f'$(od -An -N3 -t xC /dev/urandom) | sed -e 's/ /-/g')
$ echo $MAC
Details:
od (octal dump)
-An
Suppresses the leading address representation (extra noise) of the output.
-N3
Limit the output to three bytes.
-t xC
Output in hex, ASCII character style, as desired.
/dev/urandom
Linux kernel random number pseudo-file.
sed (stream editor) For space to hyphen substitution.
-e <SCRIPT>
execute the sed script.
tr (string translation) Optional, in this example. I like upper case MAC addresses in my scripts/environment.
#!/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
This should work
echo 00-60-2f-`openssl rand -hex 3 | sed 's/\(..\)/\1-/g; s/.$//'`
end=$( echo $RANDOM | openssl md5 | sed 's/\(..\)/\1-/g' | cut -b-8 )
echo 00-60-2f-$end
This is works in classic shell (#!/bin/sh
) script:
random_mac() {
printf '%.2x\n' "$(shuf -i 0-281474976710655 -n 1)" | sed -r 's/(..)/\1:/g' | cut -d: -f -6
}
Or, if you want to have custom prefix:
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
}
Example usage:
$ 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
One liner (bash)
mac=$(c=0;until [ $c -eq "6" ];do printf ":%02X" $(( $RANDOM % 256 ));let c=c+1;done|sed s/://)
result
$ echo $mac
93:72:71:0B:9E:89
This one works as well. The output is all in upper case as required.
openssl rand -hex 3 | sed 's/\(..\)\(..\)\(..\)/00-60-2F-\1-\2-\3/' | tr [a-f] [A-F]
Another option is to use jot
:
echo 00-60-2F-$(jot -w%02X -s- -r 3 0 256)
-w
changes the format, -s
changes the separator, and -r
generates random numbers.
The commands using od
in the answers posted by artistoex and zero2cx add extra dashes to the output with OS X's od
, but this does not:
echo 00-60-2f-$(od -tx1 -An -N3 /dev/random|awk '$1=$1'|tr \ -)
OS X's od
(/usr/bin/od
below) uses a different output format than GNU od
:
$ /usr/bin/od -N3 -tx1 -An /dev/random|tr ' ' -
-----------c7--fd--55----------------------------------------------------
$ god -N3 -tx1 -An /dev/random|tr ' ' -
-94-9e-5c
In Linux:
printf '00-60-2f-' && cut -b 7-11,24-26 /proc/sys/kernel/random/uuid
Explanation:
In Linux /proc/sys/kernel/random/uuid
returns a new type 4 (random) UUID every time you read it. Most of its characters are (pseudo)random hexadecimal digits, thus we can use them. E.g:
$ 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
Now it's enough to print 00-60-2f-
(without newline) first:
$ printf '00-60-2f-' && cut -b 7-11,24-26 /proc/sys/kernel/random/uuid
00-60-2f-86-f9-21
Pros:
printf
and cut
are POSIX tools;Cons:
/proc/sys/kernel/random/uuid
may not be available on some systems;
echo -n 00-60-2F; dd bs=1 count=3 if=/dev/random 2>/dev/null |hexdump -v -e '/1 "-%02X"'