Is there a portable way to programmably obtain the CPU vendor info on POSIX systems in shell scripts? In particular, I need to tell whether an x86_64/AMD64 CPU is vended by Intel or AMD. The approach does not have to work on all POSIX systems, but it should work on a decent range of common POSIX systems: GNU/Linux, MacOS, and *BSD. As an example, a Linux only approach is to extract the info from /proc/cpuinfo
.

- 8,018
- 2
- 41
- 69
-
[CPUID](https://en.wikipedia.org/wiki/CPUID) ? – jhnc Dec 02 '19 at 20:58
-
1@jhnc Yes -- but how to? – xuhdev Dec 02 '19 at 21:15
-
@jhnc : shell scripts are interpreted text; you would need a native binary executable (ELF, MachO, whatever) for each different OS to run the `cpuid` instruction, unless there's a widely installed Python or other portable language wrapper / binding for it. – Peter Cordes Dec 02 '19 at 23:53
-
I don't think there's a portable solution. I suspect that most tools that need this sort of information first detect on which OS they are running and then use an os-specific solution to get the CPU information. – larsks Dec 02 '19 at 23:53
-
2You could inspect the source code of [`inxi -C`](https://github.com/smxi/inxi) to see how they retrieve the data. `inxi` is written in `perl` which is often pre-installed, even on OS X. `perl` commands can be run as one-liners from inside `bash`. – Socowi Dec 02 '19 at 23:54
-
3I believe posix does not specify the way to extract "cpu vendor". As such everything is operating system specific and you should handle all possible operating systems separately. – KamilCuk Dec 03 '19 at 01:26
-
`dmidecode`? [What is the equivalent of /proc/cpuinfo on FreeBSD v8.1?](https://stackoverflow.com/questions/4083848/what-is-the-equivalent-of-proc-cpuinfo-on-freebsd-v8-1) -- will also work on Linux -- no clue about Mac. – David C. Rankin Dec 03 '19 at 06:53
-
[Intel suggestions](https://www.intel.com/content/www/us/en/support/articles/000006059/processors.html); `cpuid_tool` from [libcpuid](https://github.com/anrieff/libcpuid) – jhnc Dec 04 '19 at 12:44
-
No Perl 1 liner will work cross platform. Only amd/intel are easy to detect on Linux, the other types vary widely. BSDs also vary widely os to os. inxi does well, but it's not an easy thing, it's not a posix feature so you have to dig into it case by case. Then OSX tosses it all out the window and offers absurd methods, non standard features, really not a BSD anymore. Most of the real BSDs can be handled via sysctl, but that data also varies not only os to os, but release to release of the same os. – Lizardx Dec 08 '19 at 21:25
-
On a Mac, try `sysctl machdep.cpu.brand_string` – Mark Setchell Dec 08 '19 at 21:55
3 Answers
POSIX (IEEE Std 1003.1-2017) does not mandate a system utility or shell variable holding the CPU brand. The closest you'll get is uname -m
, which is the "hardware type on which the system is running". Unfortunately, that command doesn't have standardized output, so while you might get amd64
on some older machines, you'll mostly get i686
or x86_64
these days.
POSIX does mandate c99
, a basic C compiler interface, be present when a C compiler is available at all. You can use that to compile a naive version of cpuid
:
$ cat cpuid.c
#include <stdio.h>
#include <string.h>
#include <stdint.h>
int main() {
uint32_t regs[4] = { 0 };
char brand[13] = { 0 };
#ifdef _WIN32
__cpuidex((int *)regs, 0, 0);
#else
__asm volatile("cpuid" : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3]) : "a" (0), "c" (0));
#endif
memcpy(&brand[0], ®s[1], 4);
memcpy(&brand[4], ®s[3], 4);
memcpy(&brand[8], ®s[2], 4);
printf("%s\n", brand);
return 0;
}
On a variety of test machines, here's what I get:
$ c99 -o cpuid cpuid.c && ./cpuid # MacOS X
GenuineIntel
$ c99 -o cpuid cpuid.c && ./cpuid # Intel-based AWS EC2 (M5)
GenuineIntel
$ c99 -o cpuid cpuid.c && ./cpuid # AMD-based AWS EC2 (T3a)
AuthenticAMD
Wikipedia lists numerous other possible vendor brands based on the cpuid
instruction, but the ones likely most interesting for your defined use case are:
GenuineIntel
- IntelAMDisbetter!
- AMDAuthenticAMD
- AMD
Provided you had this simple executable available in your path, the POSIX-y logic would look like:
if cpuid | grep -q AMD; then
: # AMD logic here
elif cpuid | grep -q Intel; then
: # Intel logic here
else # neither Intel nor AMD
echo "Unsupported CPU vendor: $(cpuid)" >&2
fi
If you have a very, very old multi-core motherboard from the days when AMD was pin-equivalent with Intel, then you might care to know if CPU0 and CPU1 are the same vendor, in which case the C program above can be modified in the assembly lines to check processor 1 instead of 0 (the second argument to the respective asm functions).
This illustrates one particular benefit of this approach: if what you really want to know is whether the CPU supports a particular feature set (and are just using vendor as a proxy), then you can modify the C code to check whether the CPU feature is actually available. That's a quick modification to the EAX value given to the assembly code and a change to the interpretation of the E{B,C,D}X result registers.
With regards to the availability of c99
, note that:
A POSIX conforming system without
c99
is proof that no C compiler's available on that system. If your target systems do not havec99
, then you need to select and install a C compiler (gcc, clang, msvc, etc.) or attempt a fallback detection with eg/proc/cpuinfo
.The standard declares that "Unlike all of the other non-OB-shaded utilities in this standard, a utility by this name probably will not appear in the next version of this standard. This utility's name is tied to the current revision of the ISO C standard at the time this standard is approved. Since the ISO C standard and this standard are maintained by different organizations on different schedules, we cannot predict what the compiler will be named in the next version of the standard." So you should consider compiling with something along the lines of
${C99:-c99} -o cpuid cpuid.c
, which lets you flex as the binary name changes over time.

- 37,830
- 11
- 104
- 139
-
2Might fall back to `cc` if `c99` isn't available. Sure, it's not guaranteed, but it's also very likely to be present. – Charles Duffy Dec 09 '19 at 20:31
-
1`#ifdef _WIN32` Perhaps you want `#ifdef _MSC_VER`. Unless MinGW or Cygwin GCC either doesn't define `_WIN32` or *does* define `__cpuidex`? Also worth pointing out that GCC/clang come with a `cpuid.h` wrapper. Not sure that the state of portable CPU detection is in C, though. – Peter Cordes Dec 09 '19 at 21:33
-
https://www.sandpile.org/x86/cpuid.htm#level_0000_0000h also has CPUID tables. – Peter Cordes Dec 09 '19 at 21:34
I would proceed writing exact commands to get the cpu vendor for every supported OS and then run the appropriate set of commands for the given OS detection.
I wrote an example that can be easily improved / extended, taking in consideration the Operating Systems in your question:
OS="`uname`"
case "$OS" in
SunOS*) /usr/platform/`uname -m`/sbin/prtdiag -v ;;
Darwin*) sysctl -n machdep.cpu.vendor ;;
Linux*) lscpu | grep Vendor | awk '{print $NF}' ;;
FreeBSD*) sysctl -n hw.model | awk 'NR==1{print $NF}' ;;
*) echo "unknown: $OS" ;;
esac

- 8,229
- 3
- 42
- 51
-
yes, that's crudely how you do it, except for windows, he didn't specify that. Note that darwin is a subset of bsd, so basicall you want if linux/if bsd then tests within bsd, since some methods are shared and sometimes similar methods will work on darwin and freebsd/dragonfly, and may also work on openbsd, so you have to determine this beforehand. – Lizardx Dec 08 '19 at 21:54
-
@Lizardx The list I've provided is just an Example. I would just connect on the terminal where the job has to be done, echo $OSTYPE and add the result to the list. Then prepare the oneliner or little script to get the data on that specific $OSTYPE and add it to the above if ... elif structure. It is an iterative work made by testing and trial and error. Hoping to write the sacred graal immediately is imho just wishful thinking. Anyway, for clarity, I've removed the extra lines. Thanks for your input! – Pitto Dec 08 '19 at 21:57
-
Yep, determining the ostype is my step 1. But it's important to realize how many bsds there are, and to know which have similar and which have different field names / values in their output from the various commands. That's why you don't actually do it os type by type, you have to do it by os family by family, after determining which family has which members in it. Since this is a very simple thing he wants to do, it may be that there are only 2 bsd families for example, which all the types belong to. This assumes that he really only needs intel/amd ID though, if it's more, forget it. – Lizardx Dec 08 '19 at 22:00
-
2For example, dragonfly is in the freebsd family, as is pcbsd and other variants, so generally what you want is to determine which bsd grouping it's data is going to be in, each bsd insists it is its own os, even though they usually are just variants of one primary one. Basically you cover 88% of all nix systems with linux in a few lines of code, then you end up with a big mess trying to handle the bsds, it's a question of diminishing returns, and if you are getting paid to do the job or not at that point. – Lizardx Dec 08 '19 at 22:04
-
Good point. It all boils down to differencies between families and commands used to gather the data that the OP is looking for. If the CIs are available a bit of time and testing will quickly allow him to build a script that works for many. Then, when it doesn't work on a new / not foreseen CI, all it needs is a new implementation / fix. – Pitto Dec 08 '19 at 22:07
-
1I view bsd support as programming man hours / user base of the OS. This yields Linux then Freebsd/dragonfly/pcbsd and related, then openbsd, then, way behind those, netbsd. Then opensolaris and related... Except for OSX, which isn't free software, so it doesn't count. Then if the detection suddenly suffers from feature creep, then again, forget it, and just stop, unless you are getting paid to do the work, or are temporarily obsessed by the problem. It's very easy to type a question re posix type cross platform/os support, but it's an entirely different thing to actually achieve it. – Lizardx Dec 08 '19 at 22:09
-
@CharlesDuffy It is obvious that OSTYPE does not provide CPU vendor. As explained in answer and in comments this is just how I'd handle the OS difference check. How to get the CPU vendor changes from OS to OS (lscpu on Linux, for example). I do not have all the OSTYPE available to write the full code but this is in the end the logic that has to be used (as you can see confirmed by the mostly voted answer so far) – Pitto Dec 09 '19 at 20:26
-
If you don't do an OS difference check then you'll have to write / compile / deploy software on the target machines and this will be imho not feasible. OS check is something mandatory and then specific OS commands will have to be written. I've removed the [[, that is indeed a good point. I've added a Linux example in the code for clarity. – Pitto Dec 09 '19 at 20:32
-
@bishop Because I suppose that would involve deploying the software on each Server that needs to be tested... I've updated my snippet with a working Linux command that returns just the Vendor. The same should be done for other OSes but I have no access to such Servers at the moment. Let me see if I can find something... – Pitto Dec 09 '19 at 20:54
-
1@Pitto "I suppose that would involve deploying the software on each Server" -- how is that infeasible, though? It's trivially easy `echo $code > /tmp/cpuid.c && c99 -o /tmp/cpuid cpuid.c && /tmp/cpuid | grep -q AMD` and reliably gets the job done in a POSIX way, without having to figure out, track, and maintain OS and OS version specific commands. – bishop Dec 09 '19 at 21:00
-
Problem is related to environment. I suppose that this is not a person having this kind of issue in his home and often in several professional scenarios it is not allowed to install software on the servers (security / risk). Using standard OS tools will be the easier way. – Pitto Dec 09 '19 at 21:02
-
@bishop If I had a bsd machine I'd be pleased to provide more precise commands – Pitto Dec 09 '19 at 21:03
-
2"It is not allowed to install software on the servers (security / risk). Using standard OS tools will be the easier way " -- We're probably to have to agree to disagree here. Compiling a program in `/tmp` (or `$HOME/tmp`) has never been blocked on any server I've ever administered in 30 years. While I would generally always favor using "standard tools", the fact remains there _is not a standard tool_ of any kind to get this information. You literally have to ask the CPU. – bishop Dec 09 '19 at 21:06
-
-
3Yes, except for two things: 1) your darwin branch doesn't work on the [AMD-OSX](https://amd-osx.com/) Hackintosh patch -- though arguably this is a bug in their implementation and 2) you'll want to normalize the output so that the consumer doesn't have to know all possible outputs from all these variations. Maybe of concern is a) that values from sysctl can be spoofed, so aren't reliable and b) you've not said how OSTYPE should be populated -- it's a bash-ism and not POSIX. – bishop Dec 09 '19 at 21:17
-
1@bishop: you might or might not want to respect CPU-vendor spoofing, depending on the use-case. But good point that it exists for some methods of querying. – Peter Cordes Dec 09 '19 at 21:30
-
Thanks for the cleanup, @CharlesDuffy ! I've also added a version that doesn't use OSTYPE, bishop. – Pitto Dec 10 '19 at 14:35
-
1Works for me, +1, though I would still normalize the output so consumers see a whole abstraction. :) – bishop Dec 11 '19 at 03:04
-
1Very happy and proud that you liked it better now, @bishop I need to get access to similar servers and make the output nicer, fully agreed. If my daughter gives me some time I'll go hunting during the weekend and update the script. Thanks! – Pitto Dec 11 '19 at 09:39
This is the basic logic you need:
Detect OS type: linux OR BSD if BSD darwin OR other bsd. If other BSD, openbsd, freebsd, netbsd, dragonfly bsd. If darwin, you'll need darwin specific handling. If not a bsd and not linux, is it a proprietary type Unix? Are you going to try to handle it? If not, you need a safe fallback. This will determine what methods you use to do some, but not all, of the detections.
If linux, it's easy if all you want is intel or amd, unless you need solid 32/64 bit detections, you specified 64 bit only, is this the running kernel or the cpu? So that has to be handled if it's relevant. Does it matter what type of intel/amd cpu it is? They make some SOC variants for example.
sysctl for BSDs will give whatever each BSD decided to put in there. dragonfly and freebsd will be similar or the same, openbsd you have to check release to release, netbsd... is tricky. Some installs will require root to read sysctl, that's out of your hands, so you have to handle it case by case, and have error handling to detect root required, that varies, the usual is to make it user readable data, but not always. Note that the bsds can and do change the syntax of some field's data in the output, so you have to keep up on it if you actually want bsd support. Apple in general does not seem to care at all about real unix tools being able to work with their data, so it's empirical, don't assume without seeing several generations of the output. And they don't include a lot of standard unix tools by default so you can't assume things are actually installed in the first place.
/proc/cpuinfo will cover all linux system for amd/intel, and a variety of methods can be used to pinpoint if it's running 32 bit or 64 bit, and if it's a 32 or 64 bit cpu.
vm's can help, but only go part of the way since the cpu will be your host machine's, or part of it. Getting reliable current and last generation data that is reliable and real is a pain. But if you have intel and amd systems to work with, you can install most of the bsd variants except darwin/osx and debug on those, so that gets you to most of the os types, except darwin, which requires having a mac of some type available.
Does failure matter? Does it actually matter if the detection fails? If so, how is failure handled? Does ARM/MIPS/PPC matter? What about other CPUs, like Elbrus? that have many intel-like features, but which are not amd or intel?
Like the comment said, read the cpu block in inxi to pick out what you need, but it's not easy to do, and requires a lot of data examples, and you'll be sad because one day FreeBSD or osx or openbsd will change something at total random for a new release.
If you ignore OSX, and pretend it doesn't exist, on the bright side, you'll get 98% support out of the box with very little code if all you need is intel/amd detection via /proc/cpuinfo, that prints it out as neat as can be desired. If you must have OSX, then you have to add the full suite of BSD handlers, which is a pain. Personally I wouldn't touch a project like that unless I got paid to do it, re OSX. Usually you can get FreeBSD and maybe OpenBSD reasonably readily, though you have to check every new major release to see if it all still works.
If you add more requirements, like cpus other than intel/amd, then it gets a lot harder and takes much more code.
Note that on darwin, currently all osx is I believe intel, though there's rumors apple is looking to leave intel. previously they were powerpc, so it also comes down to how robust the solution has to be, that is, do you care if it fails on a mac powerpc? do you care if it fails on a future mac that is not intel powered?
Further note that if BSD is specified, that excludes a wide variety of even more fragmented Unix systems, like openindiana, solaris proper, the proprietary unices of ibm, hp, and so on, which all use different tools.

- 1,165
- 10
- 16