What command can I use to retrieve the system's serial number from the unix command line? As uname will output some information about the software and hardware, I would like to retrieve the serial number from a command to use in a script.
- 235,889
7 Answers
The system_profiler command provides a direct answer that’s easily human readable (assuming you are on 10.3 or newer), but you can also use ioreg for the task as it generally completes faster.
system_profiler SPHardwareDataType is the data type that contains the core hardware information, and you can use grep or awk to pare things down further as needed:
system_profiler SPHardwareDataType | awk '/Serial/ {print $4}'
or
ioreg -l | awk '/IOPlatformSerialNumber/ { print $4;}'
Both of those commands take between 0.5 and 0.2 seconds to run on modern SSD Macs, so if you want to optimize the command and remove the " you can have your answer in 0.005s or so:
ioreg -c IOPlatformExpertDevice -d 2 | awk -F\" '/IOPlatformSerialNumber/{print $(NF-1)}'
- 235,889
C++ example from https://developer.apple.com/library/archive/technotes/tn1103/_index.html:
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
std::string
getSerialNumber()
{
CFStringRef serial;
char buffer[32] = {0};
std::string seriaNumber;
io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceMatching("IOPlatformExpertDevice"));
if (platformExpert)
{
CFTypeRef serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert,
CFSTR(kIOPlatformSerialNumberKey),
kCFAllocatorDefault, 0);
if (serialNumberAsCFString) {
serial = (CFStringRef)serialNumberAsCFString;
}
if (CFStringGetCString(serial, buffer, 32, kCFStringEncodingUTF8)) {
seriaNumber = buffer;
}
IOObjectRelease(platformExpert);
}
return seriaNumber;
}
- 100,768
- 49
This works in Python 3.10.5 on macOS
import json
import os
import time
Example MySPHardwareDataType.json created and used by this script
#{
"SPHardwareDataType" : [
{
"_name" : "hardware_overview",
"activation_lock_status" : "activation_lock_disabled",
"boot_rom_version" : "7459.121.3",
"chip_type" : "Apple M1",
"machine_model" : "MacBookPro17,1",
"machine_name" : "MacBook Pro",
"number_processors" : "proc 8:4:4",
"os_loader_version" : "7459.121.3",
"physical_memory" : "16 GB",
"platform_UUID" : "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"provisioning_UDID" : "XXXXXXXX-XXXXXXXXXXXXXXXX",
"serial_number" : "XXXXXXXXXXXX"
}
]
#}
def export_basic_hwinfo_to_json(json_filename_and_path):
# This is the command that will execute. It will run macOS' built-in
# system_profiler binary, filtered to only show the contents of
# SPHardwareDataType, which contains the data we are looking for.
# Additionally, we have also specified that it should be exported to JSON
# format, and that standard output should be redirected to the file specified earlier
command = "system_profiler SPHardwareDataType -json >" + json_filename_and_path
# execute the command
os.popen(command)
# This loop waits for the file to exist before continuing
while os.path.exists(json_filename_and_path) is False:
time.sleep(1)
def get_serial(json_filename_and_path) -> str:
# open the .json file for processing
file_handle = open(json_filename_and_path)
# load the contents of the .json file into a Python dictionary
hw_info_dict = json.load(file_handle)
# retrieve the data we are looking for
serial = hw_info_dict['SPHardwareDataType'][0]['serial_number']
return serial
def get_machine_sku(json_filename_and_path) -> str:
# open the .json file for processing
file_handle = open(json_filename_and_path)
# load the contents of the .json file into a Python dictionary
hw_info_dict = json.load(file_handle)
# retrieve the data we are looking for
machine_sku = hw_info_dict['SPHardwareDataType'][0]['machine_model']
return machine_sku
def get_model(json_filename_and_path) -> str:
# open the .json file for processing
file_handle = open(json_filename_and_path)
# load the contents of the .json file into a Python dictionary
hw_info_dict = json.load(file_handle)
# retrieve the data we are looking for
model = hw_info_dict['SPHardwareDataType'][0]['machine_name']
return model
def main():
# We are going to store the output file in a temp directory
temp_dir: str = os.environ.get('TMPDIR')
temp_dir: str = temp_dir[:-1]
json_filename: str = "MySPHardwareDataType.json"
# Cleanly append the name of the output file to the file path
json_filename_and_path: str = os.sep.join([temp_dir, json_filename])
export_basic_hwinfo_to_json(json_filename_and_path)
serial: str = get_serial(json_filename_and_path)
machine_sku: str = get_machine_sku(json_filename_and_path)
model: str = get_model(json_filename_and_path)
print(F"serial={serial}")
print(F"machine_sku={machine_sku}")
print(F"model={model}")
if name == "main":
main()
- 21
- 2
-
You are welcome! – user2104962 Jul 06 '22 at 19:09
To make it easier to remember, use a case insensitive search:
ioreg -l | grep -i serialnumber | grep -i platform
- 4,057
- 19
- 1
-
Warning: this returns a line | "IOPlatformSerialNumber" = "YourSerialNumber" That’s fine visually but if you use it in a script you'll need to pipe it to awk. – jasonology Jun 25 '19 at 04:28
If you don't want to count columns you can rely on the fact that the value is always in the last one and use
system_profiler SPHardwareDataType | awk '/Serial/{print $NF}'
- 100,768
- 101
- 1
-
gee, thanks mom @nohillside; we wouldn't want to subject people to anything that isn't kid gloves and kudos, you know, like reality. – christian elsee Jul 04 '21 at 00:56
-
SE works a bit different than forum sites. The way to give kudos is to upvote posts you like or which helped you. – nohillside Jul 04 '21 at 06:18
-
I wasnt giving kudos @nohillside, I was criticizing the members of the thread that managed to waste time and misinform by discussing benchmarks around ioreg and system_profiler, giving weight to something that NO ONE outside of exceptional circumstances will ever concern themselves with. My beef, is that one day a junior ops engineer, will point to this or something like it, when defending a pull request that "optimizes" the serial-number-as-a-rube-goldberg-service, which is famously held together with spit and tape. Maybe balancing the carrot with the stick will help lead to less of that. – christian elsee Jul 04 '21 at 23:29
-
Please have a look at https://apple.stackexchange.com/help/how-to-answer for what we look for in answers. Also, this is a Q&A site not a forum, answers should stand on their own and not discuss other answers. If you want to discuss or criticize other answers, please use comments beneath that answer or the chat. – nohillside Jul 05 '21 at 04:12
It's potentially slightly cleaner to use the XML output of ioreg rather than parsing the human-readable form with sed/awk:
ioreg -c IOPlatformExpertDevice -d 2 -a | xmllint --xpath "/plist/dict[key='IORegistryEntryChildren']/array/dict/key[.='IOPlatformSerialNumber']/following-sibling::string[1]/node()" -
- 1