Shell 脚本:在 POSIX 系统上以可编程方式获取 CPU 供应商的可移植方式
Shell script: Portable way to programmably obtain the CPU vendor on POSIX systems
是否有一种可移植的方法可以在 shell 脚本中以编程方式获取 POSIX 系统上的 CPU 供应商信息?特别是,我需要判断 x86_64/AMD64 CPU 是由 Intel 还是 AMD 销售的。该方法不一定适用于所有 POSIX 系统,但它应该适用于相当范围内的常见 POSIX 系统:GNU/Linux、MacOS 和 *BSD。例如,仅 Linux 的方法是从 /proc/cpuinfo
.
中提取信息
这是你需要的基本逻辑:
检测 OS 类型:linux 或 BSD,如果是 BSD darwin 或其他 bsd。如其他BSD、openbsd、freebsd、netbsd、dragonfly bsd。如果是达尔文,您将需要达尔文特定的处理。如果不是 bsd 也不是 linux,它是专有类型的 Unix 吗?你会尝试处理它吗?如果没有,您需要一个安全的后备方案。这将决定您使用什么方法进行部分检测,但不是全部检测。
如果linux,你只要intel或者amd就好了,除非你需要可靠的32/64位检测,你只指定了64位,这是运行内核还是cpu?所以如果它是相关的,就必须处理它。它是什么类型的 intel/amd cpu 重要吗?例如,他们制作了一些 SOC 变体。
BSD 的 sysctl 将提供每个 BSD 决定放入其中的任何内容。 dragonfly 和 freebsd 将是相似或相同的,openbsd 你必须检查发布才能发布,netbsd... 很棘手。一些安装将需要 root 来读取 sysctl,这是你无法控制的,所以你必须逐个处理它,并且有错误处理来检测需要 root,这各不相同,通常是让它成为用户可读的数据,但并非总是如此.请注意,bsds 可以并且确实会更改输出中某些字段数据的语法,因此如果您确实需要 bsd 支持,则必须跟上它。一般来说,Apple 似乎根本不关心真正的 unix 工具能够处理他们的数据,所以这是经验主义的,不要在没有看到几代输出的情况下假设。默认情况下,它们不包含很多标准的 unix 工具,因此您不能假设这些东西实际上已经安装在第一位。
/proc/cpuinfo会覆盖amd/intel的所有linux系统,如果是运行32位,可以用多种方法查明或 64 位,如果是 32 位或 64 位 cpu.
vm 可以提供帮助,但只能起到一部分作用,因为 cpu 将是您的 host machine,或者其中的一部分。获得可靠且真实的当前和上一代可靠数据是一件痛苦的事情。但是如果你有 intel 和 amd 系统可以使用,你可以安装 most 的 bsd 变体除了 darwin/osx 并在 those 上调试,这样你就可以 most os 类型,darwin 除外,它需要某种类型的 mac。
失败重要吗?如果检测失败真的很重要吗?如果是这样,如何处理失败? ARM/MIPS/PPC 重要吗?其他 CPU 怎么样,比如 Elbrus?具有许多类似英特尔的功能,但哪些不是 AMD 或英特尔?
就像评论说的那样,看inxi中的cpu块,挑出你需要的,但是不容易做到,需要大量的数据例子,你会难过的,因为一个天 FreeBSD 或 osx 或 openbsd 将完全随机更改一些新版本。
如果您忽略 OSX,并假装它不存在,从好的方面来说,如果您只需要 intel/amd 通过 /proc/cpuinfo 进行检测,可以尽可能整齐地打印出来。如果您必须拥有 OSX,那么您必须添加全套 BSD 处理程序,这很痛苦。就我个人而言,除非我得到报酬,否则我不会接触这样的项目,re OSX。通常你可以相当容易地获得 FreeBSD 和 OpenBSD,尽管你必须检查每个新的主要版本以查看它是否仍然有效。
如果您添加更多要求,例如 cpus 而不是 intel/amd,那么它会变得更加困难并且需要更多的代码。
请注意,在达尔文上,目前所有 osx 我相信都是英特尔,尽管有传言称苹果正在寻求离开英特尔。以前它们是 powerpc,所以它也归结为解决方案必须有多稳健,也就是说,您是否关心它是否在 mac powerpc 上失败?你关心它是否会在未来 mac 不是英特尔驱动的情况下失败吗?
进一步注意,如果指定了 BSD,则不包括各种甚至更分散的 Unix 系统,如 openindiana、solaris proper、ibm、hp 的专有 unices,等等,它们都使用不同的工具。
我会继续编写确切的命令,为每个受支持的 OS 获取 cpu 供应商,然后 运行 为给定的 OS 检测获取适当的命令集。
考虑到您问题中的操作系统,我写了一个可以轻松改进/扩展的示例:
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
POSIX (IEEE Std 1003.1-2017) 不强制要求 system utility or shell variable holding the CPU brand. The closest you'll get is uname -m
,即 "hardware type on which the system is running"。不幸的是,该命令没有标准化的输出,因此虽然您 可能 在一些较旧的机器上获得 amd64
,但您大多会获得 i686
或 x86_64
这些天。
POSIX 确实要求 c99
,一个基本的 C 编译器接口,在 C 编译器可用时出现。您可以使用它来编译 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;
}
在各种测试机上,我得到的是:
$ 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 根据 cpuid
说明列出了许多其他可能的供应商品牌,但对于您定义的用例最感兴趣的可能是:
GenuineIntel
- 英特尔
AMDisbetter!
- AMD
AuthenticAMD
- AMD
假设您的路径中有这个简单的可执行文件,POSIX-y 逻辑将如下所示:
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
如果您有一个非常非常旧的多核主板,那时候 AMD 与 Intel 引脚等效,那么您可能想知道 CPU0 和 CPU1 是否是同一供应商,在这种情况下,可以在装配线中修改上面的 C 程序以检查处理器 1 而不是 0(各个 asm 函数的第二个参数)。
这说明了这种方法的一个特别好处:如果您真正想知道 CPU 是否支持特定功能集(并且只是使用供应商作为代理),那么您可以修改 C 代码以检查 CPU 功能是否 实际上 可用。这是对提供给汇编代码的 EAX 值的快速修改,以及对 E{B,C,D}X 结果寄存器解释的更改。
关于 c99
的可用性,请注意:
没有c99
的POSIX符合系统证明没有 C编译器在该系统上可用。如果您的目标系统没有 c99
,那么您需要 select 并安装 C 编译器(gcc、clang、msvc 等)或尝试使用例如 /proc/cpuinfo
进行回退检测。
标准声明 "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." 因此您应该考虑使用类似于 ${C99:-c99} -o cpuid cpuid.c
的内容进行编译,这样您就可以随着二进制名称随时间的变化而灵活调整。
是否有一种可移植的方法可以在 shell 脚本中以编程方式获取 POSIX 系统上的 CPU 供应商信息?特别是,我需要判断 x86_64/AMD64 CPU 是由 Intel 还是 AMD 销售的。该方法不一定适用于所有 POSIX 系统,但它应该适用于相当范围内的常见 POSIX 系统:GNU/Linux、MacOS 和 *BSD。例如,仅 Linux 的方法是从 /proc/cpuinfo
.
这是你需要的基本逻辑:
检测 OS 类型:linux 或 BSD,如果是 BSD darwin 或其他 bsd。如其他BSD、openbsd、freebsd、netbsd、dragonfly bsd。如果是达尔文,您将需要达尔文特定的处理。如果不是 bsd 也不是 linux,它是专有类型的 Unix 吗?你会尝试处理它吗?如果没有,您需要一个安全的后备方案。这将决定您使用什么方法进行部分检测,但不是全部检测。
如果linux,你只要intel或者amd就好了,除非你需要可靠的32/64位检测,你只指定了64位,这是运行内核还是cpu?所以如果它是相关的,就必须处理它。它是什么类型的 intel/amd cpu 重要吗?例如,他们制作了一些 SOC 变体。
BSD 的 sysctl 将提供每个 BSD 决定放入其中的任何内容。 dragonfly 和 freebsd 将是相似或相同的,openbsd 你必须检查发布才能发布,netbsd... 很棘手。一些安装将需要 root 来读取 sysctl,这是你无法控制的,所以你必须逐个处理它,并且有错误处理来检测需要 root,这各不相同,通常是让它成为用户可读的数据,但并非总是如此.请注意,bsds 可以并且确实会更改输出中某些字段数据的语法,因此如果您确实需要 bsd 支持,则必须跟上它。一般来说,Apple 似乎根本不关心真正的 unix 工具能够处理他们的数据,所以这是经验主义的,不要在没有看到几代输出的情况下假设。默认情况下,它们不包含很多标准的 unix 工具,因此您不能假设这些东西实际上已经安装在第一位。
/proc/cpuinfo会覆盖amd/intel的所有linux系统,如果是运行32位,可以用多种方法查明或 64 位,如果是 32 位或 64 位 cpu.
vm 可以提供帮助,但只能起到一部分作用,因为 cpu 将是您的 host machine,或者其中的一部分。获得可靠且真实的当前和上一代可靠数据是一件痛苦的事情。但是如果你有 intel 和 amd 系统可以使用,你可以安装 most 的 bsd 变体除了 darwin/osx 并在 those 上调试,这样你就可以 most os 类型,darwin 除外,它需要某种类型的 mac。
失败重要吗?如果检测失败真的很重要吗?如果是这样,如何处理失败? ARM/MIPS/PPC 重要吗?其他 CPU 怎么样,比如 Elbrus?具有许多类似英特尔的功能,但哪些不是 AMD 或英特尔?
就像评论说的那样,看inxi中的cpu块,挑出你需要的,但是不容易做到,需要大量的数据例子,你会难过的,因为一个天 FreeBSD 或 osx 或 openbsd 将完全随机更改一些新版本。
如果您忽略 OSX,并假装它不存在,从好的方面来说,如果您只需要 intel/amd 通过 /proc/cpuinfo 进行检测,可以尽可能整齐地打印出来。如果您必须拥有 OSX,那么您必须添加全套 BSD 处理程序,这很痛苦。就我个人而言,除非我得到报酬,否则我不会接触这样的项目,re OSX。通常你可以相当容易地获得 FreeBSD 和 OpenBSD,尽管你必须检查每个新的主要版本以查看它是否仍然有效。
如果您添加更多要求,例如 cpus 而不是 intel/amd,那么它会变得更加困难并且需要更多的代码。
请注意,在达尔文上,目前所有 osx 我相信都是英特尔,尽管有传言称苹果正在寻求离开英特尔。以前它们是 powerpc,所以它也归结为解决方案必须有多稳健,也就是说,您是否关心它是否在 mac powerpc 上失败?你关心它是否会在未来 mac 不是英特尔驱动的情况下失败吗?
进一步注意,如果指定了 BSD,则不包括各种甚至更分散的 Unix 系统,如 openindiana、solaris proper、ibm、hp 的专有 unices,等等,它们都使用不同的工具。
我会继续编写确切的命令,为每个受支持的 OS 获取 cpu 供应商,然后 运行 为给定的 OS 检测获取适当的命令集。
考虑到您问题中的操作系统,我写了一个可以轻松改进/扩展的示例:
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
POSIX (IEEE Std 1003.1-2017) 不强制要求 system utility or shell variable holding the CPU brand. The closest you'll get is uname -m
,即 "hardware type on which the system is running"。不幸的是,该命令没有标准化的输出,因此虽然您 可能 在一些较旧的机器上获得 amd64
,但您大多会获得 i686
或 x86_64
这些天。
POSIX 确实要求 c99
,一个基本的 C 编译器接口,在 C 编译器可用时出现。您可以使用它来编译 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;
}
在各种测试机上,我得到的是:
$ 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 根据 cpuid
说明列出了许多其他可能的供应商品牌,但对于您定义的用例最感兴趣的可能是:
GenuineIntel
- 英特尔AMDisbetter!
- AMDAuthenticAMD
- AMD
假设您的路径中有这个简单的可执行文件,POSIX-y 逻辑将如下所示:
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
如果您有一个非常非常旧的多核主板,那时候 AMD 与 Intel 引脚等效,那么您可能想知道 CPU0 和 CPU1 是否是同一供应商,在这种情况下,可以在装配线中修改上面的 C 程序以检查处理器 1 而不是 0(各个 asm 函数的第二个参数)。
这说明了这种方法的一个特别好处:如果您真正想知道 CPU 是否支持特定功能集(并且只是使用供应商作为代理),那么您可以修改 C 代码以检查 CPU 功能是否 实际上 可用。这是对提供给汇编代码的 EAX 值的快速修改,以及对 E{B,C,D}X 结果寄存器解释的更改。
关于 c99
的可用性,请注意:
没有
c99
的POSIX符合系统证明没有 C编译器在该系统上可用。如果您的目标系统没有c99
,那么您需要 select 并安装 C 编译器(gcc、clang、msvc 等)或尝试使用例如/proc/cpuinfo
进行回退检测。标准声明 "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." 因此您应该考虑使用类似于
${C99:-c99} -o cpuid cpuid.c
的内容进行编译,这样您就可以随着二进制名称随时间的变化而灵活调整。