Set part of serial to become a variable

aporzio1
New Contributor II

I am making a bash script to change the password to include part of the serial number, but I only need the last 5 digits.

Using this I can set serial as a variable to the full serial number.

serial="$(ioreg -l | grep IOPlatformSerialNumber | sed -e 's/.*"(.*)"/1/')"

Is there a way to ignore everything but the last 5 characters?

15 REPLIES 15

apizz
Valued Contributor

I would recommend using system_profiler rather than ioreg. You can get the serial number faster. See my results below:

mymac:~ user$ time system_profiler SPHardwareDataType | awk '/Serial/ {print $4}'
F5KRW07FF9VM

real    0m0.196s
user    0m0.068s
sys 0m0.047s

mymac:~ user$ time ioreg -l | grep IOPlatformSerialNumber
    |   "IOPlatformSerialNumber" = "F5KRW07FF9VM"

real    0m1.049s
user    0m0.262s
sys 0m0.845s

Mac serial numbers are 12 digits, so you could use sed to remove the first 7 characters just to get the last 5.

Your command would then be the following.

system_profiler SPHardwareDataType | awk '/Serial/ {print $4}' | sed 's/^.{7}//g'

aporzio1
New Contributor II

@aporlebeke

So I ran

system_profiler SPHardwareDataType | awk '/Serial/ {print $4}' | sed 's/^.{7}//g'

in terminal but it still returns the full 12 digits

apizz
Valued Contributor

Oops. I copied and pasted and it removed a backslash.

6a08644f02bd473095487602f3069a16

bvrooman
Valued Contributor

Mac serial numbers are 12 or 13 characters. There might be something more efficient, but here's what I came up with to grab the last 5 characters:

system_profiler SPHardwareDataType | awk '/Serial/ {print $4}' | rev | cut -c -5 | rev

apizz
Valued Contributor

@bvrooman I learned something!

apizz
Valued Contributor

@bvrooman I learned something!

mm2270
Legendary Contributor III

@aporlebeke I disagree. If you know what you're doing with ioreg, it's much faster than system_profiler

time system_profiler SPHardwareDataType | awk '/Serial/ {print $4}'
C02N65YZG3QK

real    0m0.455s
user    0m0.138s
sys 0m0.125s
time ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformSerialNumber/{print $4}'
C02N65YZG3QK

real    0m0.022s
user    0m0.004s
sys 0m0.020s

As for getting the last 5 digits, there's no need to reverse it, pass it through cut and reverse it again. tail can do it by itself, but you need to add one to the number, meaning to get the last 5 characters, tell it to tail by 6 characters.

ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformSerialNumber/{print $4}' | tail -c 6
ZG3QK

Hope that helps.

apizz
Valued Contributor

@mm2270 learned something new again! Thanks

bvrooman
Valued Contributor

@mm2270 Ah, I forgot that tail can do characters. I'm so used to using it for following logs that I never think of it for anything else.

KSchroeder
Contributor

Just a thought...the last 5 of a serial number don't seem to be very unique...looking at our machines, it seems the first three (i.e. C02) and last 4 are identical across many machines of the same model/year; wouldn't you want the middle 5 or 6 characters? Those seem to be the unique ones. For example, "G8WP" seems to be the identifier suffix for mid-2015 15" Retina MBP.

I dumped out our inventory and used =LEFT(B2,3), =MID(B2,4,5), and =RIGHT(B2,4) against the serial number column and the results are pretty convincing:
Row Labels Count of Last 4
G8WP 510
FVH8 140
G3QD 86
FD57 49
GCN3 47
FFT0 16
H3QF 13
FD56 12

Looking at the same data for the "middle5" (via the MID() function) shows only 2 that are duplicate, and they were two different models, 1 a 13" 2015 MBA, and the other a 13" 2015 MBP.

KSchroeder
Contributor

Now don't ask me to write an awk or sed to extract that...my shell-fu is still pretty weak...but i'm sure one of these fine individuals above know how to replicate the "MID" function in Excel with awk/sed/etc.

donmontalvo
Esteemed Contributor III

@mm2270 love the time command...puts everything into proper perspective. :D

--
https://donmontalvo.com

mm2270
Legendary Contributor III

@KSchroeder You make a good point about the last 5 of the serial not being particularly unique. I don't know for sure how @aporzio1 had planned on using that string. He mentions using it as part of a password, but I don't know any more beyond that or what else it would be combined with.

Another option for a unique string to grab from the system might be one section of the UUID string.

$ ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformUUID/{print $4}' | cut -d- -f2
$ D205

I doubt that 2nd (or 3rd or 4th) section of the UUID string would be very common amongst other systems.

If the serial number is what he wants to use, and assuming your point on the common-ness of the last 5 is relevant in this case, then we can grab a section from the "middle" of the Serial Number with bash parameter expansion. Unfortunately that's a little harder to do in a one-liner, or at least I haven't found a good way of doing that.

#!/bin/bash

SerNum=$(ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformSerialNumber/{print $4}')

midSerNum="${SerNum:4:6}"

echo "$midSerNum"

Result:

65YZG3

Note that with a 12 character serial number there's no exact middle 5, so the best we can do is get characters 5 - 9. With a 13 character serial number, the above expansion would give you exactly the middle 5, characters 5 - 9 with 1 - 4 on the left and 10 - 13 on the right both being discarded.

aporzio1
New Contributor II

We do not need it to be a different one on each computer, just need it to not be universally the same. Not my rules, but I follow them...

anyways what I am looking to do is something like this

sysadminctl -addUser user -fullName user -password "{system_profiler SPHardwareDataType | awk '/Serial/ {print $4}' | rev | cut -c -5 | rev}extrawords" -admin

Where the password is set to the last 5 of the serial number followed by a string of text

ex. QG1J2extrawords would be the password

mm2270
Legendary Contributor III

@aporzio1 Not sure if you saw the posts above, but 1) I would consider using ioreg to get the Serial Number as I showed above, not system_profiler, since the former is a bit faster, and 2) you also don't need to do the cut rev cut stuff to get the last 5. tail can do it by itself. See my post above (2nd to last one) for the code example.

Lastly, you have curly braces in the front and end of the command that is getting the last 5 from the serial, but that won't work. I think you're looking for a $( at the start and a closing ) at the end.