47

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.

7 Answers 7

67

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)}'
0
18

This also works…

ioreg -l | grep IOPlatformSerialNumber
0
4

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;
}
0
2

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()
1
  • You are welcome! Commented Jul 6, 2022 at 19:09
1

To make it easier to remember, use a case insensitive search:

ioreg -l | grep -i serialnumber | grep -i platform
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
    Commented Jun 25, 2019 at 4:28
0

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}'
4
  • gee, thanks mom @nohillside; we wouldn't want to subject people to anything that isn't kid gloves and kudos, you know, like reality. Commented Jul 4, 2021 at 0: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
    Commented Jul 4, 2021 at 6: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. Commented Jul 4, 2021 at 23:29
  • Please have a look at 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
    Commented Jul 5, 2021 at 4:12
0

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()" -

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .