Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

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?

share|improve this question
2  
echo -n 00-60-2F; dd bs=1 count=3 if=/dev/random 2>/dev/null |hexdump -v -e '/1 "-%02X"' –  artistoex Jan 20 '12 at 13:56
    
@artistoex That was beautiful... Why did you not post that as the answer? –  bobmagoo Aug 25 '12 at 0:22

10 Answers 10

  1. Generate an appropriately sized int like so: http://tldp.org/LDP/abs/html/randomvar.html
  2. Convert to hex like so: http://snipplr.com/view/2428/convert-from-int-to-hex/
  3. Add the dashes between three randomly generated chunks

#!/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
share|improve this answer
    
Extra +1 if you provide an example of each (I know you are teaching him how to fish, but you could give him the pieces of the puzzle to put together, and explain how/why they work). –  Jed Daniels Jun 25 '11 at 17:35
    
@Jed Daniels - done and done. code provided. –  hbdgaf Jun 26 '11 at 18:28

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.

share|improve this answer
    
thanks for realizing that i was trying to make him learn to fish instead of spoon-feeding a solution –  hbdgaf Dec 5 '10 at 20:16
1  
You could always explain your answer so that you are both teaching him how to fish in addition to providing one this time around... –  Jed Daniels Jun 25 '11 at 17:34
#!/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.

share|improve this answer
    
It seems to need IFS= read … to avoid folding 09 0a and 20 (the usual IFS chars) into 00. –  Chris Johnsen Dec 4 '10 at 20:37
    
@Chris: Sorry, I took a couple of things out while doing some double checking and forgot to put them back in. It also needs -d ''. I'll fix my answer. Thanks for letting me know. –  Dennis Williamson Dec 4 '10 at 20:48
    
Oops, the -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. –  Chris Johnsen Dec 4 '10 at 21:21
    
@Chris: I wish my DWIM processor wasn't on the fritz. By the way, you might be interested to see a pure Bash script I wrote that duplicates the core functionality of hexdump -C. –  Dennis Williamson Dec 4 '10 at 21:58
    
Extra +1 if you can explain what is happening and why your solution works. –  Jed Daniels Jun 25 '11 at 17:33

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:

  • The printf program is based on the C "printf" function, which takes a "format string" as the first parameter and then additional parameters fill in the format string.
  • % in the format string introduces a "format specifier" which can be one or more characters telling how to format the arguments.
  • A leading zero (0) in a format specifier means that the resulting numeric output should be padded with leading zeros up to the specified width.
  • The 2 says that the specifier should be displayed taking up two characters worth of width.
  • The X ends the specifier and denotes that it should be interpreted as a number and displayed as hexidecimal. Because it's upper-case, the letters a-f should be upper case.
  • The \n is a newline -- printf interprets backslash as an escape code which can be used to display other characters, often tricky characters like the newline.
  • The remaining characters in the format specifier are printed out literally, this includes the initial "00-06-2F-" and the dashes between the format specifiers.
  • The remaining arguments are shell variable substitutions (denoted by the $) and include a math expression which is a random number (RANDOM) modulo 256. This results in a random number between 0 and 255.
share|improve this answer
    
Good point, thanks. Fixed. –  Sean Reifschneider Dec 5 '10 at 13:25
1  
As user58033 rightfully pointed out in an answer (which might be gone now): %02X would give one upper case letters. –  Arjan Dec 5 '10 at 14:17
    
Ah, good point. I spaced that the original question gave an example using upper case. Thanks for the welcome. :-) –  Sean Reifschneider Dec 5 '10 at 20:23
    
Extra +1 if you can explain what is happening and why your solution works. –  Jed Daniels Jun 25 '11 at 17:33
    
There you go, @Jed. –  Sean Reifschneider Jul 7 '11 at 1:18

The shortest way I could come up with was using hexdump directly

echo 00-60-2f$(hexdump -n3 -e '/1 "-%02X"' /dev/random)
  • -n3 tells hexdump to read three byytes
  • The format string prints a dash and a two digit hex value for each byte
    • '/1' means apply format for every read byte
    • "-%02X" is a printf spec for printing a leading zero, two digit, upper case hex value
  • /dev/random is a source random bytes

Tested on GNU/Linux

share|improve this answer
    
Unix effectiveness at work :-) –  artistoex Sep 6 '12 at 9:40
    
hexdump -n3 -e'/3 "00-60-2F" 3/1 "-%02X"' /dev/random is a little shorter :-) –  artistoex Sep 7 '12 at 8:18

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.

share|improve this answer
#!/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
share|improve this answer

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.

share|improve this answer
end=$( echo $RANDOM | openssl md5 | sed 's/\(..\)/\1-/g' | cut -b-8 )
echo 00-60-2f-$end
share|improve this answer
4  
Extra +1 if you can explain what is happening and why your solution works. –  Jed Daniels Jun 25 '11 at 17:35

This should work

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

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.