Klas Mellbourn
Klas Mellbourn

Reputation: 44347

Detect Apple Silicon from command line

How can I detect from a shell script that it is running on M1 Apple hardware?

I want to be able to run a command-line command so that I can write an if-statement whose body will only be executed when run on a mac with an M1 processor (and at least macOS Big Sur, naturally).

Upvotes: 78

Views: 45479

Answers (5)

Cœur
Cœur

Reputation: 38657

Let's address properly the situation where the command is run on a Rosetta environment (example: right-click Terminal.app in Finder > Info > Open with Rosetta).

The solutions with uname -m, uname -p and arch will all fail in this case.
The solution with sysctl -n machdep.cpu.brand_string is sensible to arbitrary brand naming evolution.

So what we really want is uname -s being "Darwin" combined with uname -v containing "ARM64". Do NOT use uname -a, which is prone to errors if the name of the machine itself contains "ARM64".

if [[ "$(uname -s)" = Darwin && "$(uname -v)" = *ARM64* ]]; then
    echo 'Apple Silicon'
else
    echo 'something else'
fi

This solution works properly with and without Rosetta, and is probably future proof.

Upvotes: 2

Just another guest
Just another guest

Reputation: 1

/usr/bin/arch is all you need. Why complicate things when there's already a program to do this for you.

Upvotes: -1

MBaas
MBaas

Reputation: 7530

I found that sysctl -n machdep.cpu.brand_string reported Apple M1 even though the process was run under Rosetta.

Update: be prepared for Apple M1 Pro, Apple M2, Apple M2 Max etc.!

Upvotes: 36

Klas Mellbourn
Klas Mellbourn

Reputation: 44347

uname -m

will return arm64 as opposed to x86_64

if [[ $(uname -m) == 'arm64' ]]; then
  echo M1
fi

or, as @chepner suggested

uname -p

will return arm as opposed to i386

if [[ $(uname -p) == 'arm' ]]; then
  echo M1
fi

yet another tool is arch:

if [[ $(arch) == 'arm64' ]]; then
  echo M1
fi

Upvotes: 106

balupton
balupton

Reputation: 48620

When using the native shell say /bin/bash -i or /bin/zsh -i, Klas Mellbourn's answer works as expected.

If using a shell that was installed via an Intel/Rosetta Homebrew installation, then uname -p returns i386, and uname -m returns x86_64, as indicated by Datasun's comment.


To get something that works across environments (Apple Silicon Native, Rosetta Shell, Linux, Raspberry Pi 4s), I use the following from the dorothy dotfile ecosystem:

is-mac && test "$(get-arch)" = 'a64'

If you aren't using dorothy, the relevant code from dorothy is:

https://github.com/bevry/dorothy/blob/1c747c0fa6bb3e6c18cdc9bae17ab66c0603d788/commands/is-mac

test "$(uname -s)" = "Darwin"

https://github.com/bevry/dorothy/blob/1c747c0fa6bb3e6c18cdc9bae17ab66c0603d788/commands/get-arch

arch="$(uname -m)"  # -i is only linux, -m is linux and apple
if [[ "$arch" = x86_64* ]]; then
    if [[ "$(uname -a)" = *ARM64* ]]; then
        echo 'a64'
    else
        echo 'x64'
    fi
elif [[ "$arch" = i*86 ]]; then
    echo 'x32'
elif [[ "$arch" = arm* ]]; then
    echo 'a32'
elif test "$arch" = aarch64; then
    echo 'a64'
else
    exit 1
fi

Jatin Mehrotra's answer on a duplicate question gives details on how to get the specific CPU instead of the architecture. Using sysctl -n machdep.cpu.brand_string outputs Apple M1 on my M1 Mac Mini, however outputs the following on a Raspberry Pi 4 Ubuntu Server:

> sysctl -n machdep.cpu.brand_string
Command 'sysctl' is available in the following places
 * /sbin/sysctl
 * /usr/sbin/sysctl
The command could not be located because '/sbin:/usr/sbin' is not included in the PATH environment variable.
This is most likely caused by the lack of administrative privileges associated with your user account.
sysctl: command not found

> sudo sysctl -n machdep.cpu.brand_string
sysctl: cannot stat /proc/sys/machdep/cpu/brand_string: No such file or directory

Upvotes: 13

Related Questions