65

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).

Klas Mellbourn
  • 42,571
  • 24
  • 140
  • 158

4 Answers4

88
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
Klas Mellbourn
  • 42,571
  • 24
  • 140
  • 158
  • 21
    Note that M1 users can run Terminal in Rosetta mode. In this case "uname -m" returns "x86_64". – Nusatad Jan 08 '21 at 17:33
  • 9
    it's not just if running Terminal in Rosetta, but also if whatever process runs the script happens to be running in Rosetta too. If someone runs this in a script deployed by, say, an RMM that is running via Rosetta you'll get `x86_64`. i think the `sysctl` approach is the best solution searching for 'Apple' in the string: `[[ $(sysctl -n machdep.cpu.brand_string) =~ "Apple" ]]` – bheinz Dec 16 '21 at 17:38
  • 1
    This doesn't work at all! If you are in VSCode Jupyter kernel it will say x86_64 even though I am on M2 Max. This `sysctl -n machdep.cpu.brand_string` is the best command. – Maziyar Mar 10 '23 at 10:19
  • 1
    @Maziyar "doesn't work at all" is an overstatement. If your "VSCode Jupyter" is reporting `x86_64`, then that process runs through the Rosetta emulator, which is probably not what you want since both VSCode and Jupyter support Apple Silicon. – Klas Mellbourn Mar 10 '23 at 13:15
  • point taken, I should have said not reliable depending on where it is being executed. – Maziyar Mar 11 '23 at 18:13
25

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.!

MBaas
  • 7,248
  • 6
  • 44
  • 61
  • 3
    This is what's needed to cleanly answer 'can I `arch -arm64 bash` my way out of here. Hard to believe `arch` doesn't have a `-l` to list current machine available architectures. – Joe Dec 06 '21 at 04:45
  • should be the accepted answer, except for the fact that this doesn't work on linux – airtonix Jul 25 '22 at 06:28
  • 1
    Be careful not to do an exact match. My laptop returns `Apple M1 Pro`. – Mark Aug 26 '22 at 18:24
  • 1
    A MacBook Pro 16" from 2023 (with M2 Max processor) will answer `Apple M2 Max` – Klas Mellbourn Apr 14 '23 at 15:08
12

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
balupton
  • 47,113
  • 32
  • 131
  • 182
  • 1
    If `uname -m` returns `x86_64` I think you are probably running your terminal through Rosetta. Have you checked `Open using Rosetta` in the `Get Info` dialog for the terminal program? – Klas Mellbourn Jun 27 '21 at 10:28
  • 2
    `Open using Rosetta` is unchecked: https://www.dropbox.com/s/lrhxgkxtmi2wv74/CleanShot%202021-06-28%20at%2006.24.52%402x.png?dl=0 If I run a new command `/bin/bash -i` and then run `uname -m` then it returns `arm64` and `uname -p` returns `arm`. So is caused by my default shell, which is installed by homebrew, being run through rosetta. Thanks for helping me track this down. I've updated my answer. – balupton Jun 27 '21 at 22:38
0

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

  • https://stackoverflow.com/a/65259353/619961 already provides this information. Why add it again? – ikaerom Jul 03 '23 at 18:24