• 用命令行获取操作系统名称版本+CPU等信息


    不同的开发语言/工具,获取操作系统和CPU等信息方法不一样,真的记不住。
    返回的文字方式也很多样,有时仅仅显示个Linux了事。
    但不管什么语言写的程序,都通过调用命令行来获得这些信息,则结果比较统一好看。

    (一)命令行取得信息

    (1.1)Windows

    (1.1.1)操作系统名称版本

    通过ver命令查看版本号,并且只看包含Windows字样的一行。
    不过由于Windows神奇的版本号设置,就算是Win11看到的也是10.0呢(好像22000以上就是Win11)。

    C:\>ver | find /I "Windows"
    Microsoft Windows [版本 10.0.22621.900]
    
    
    • 1
    • 2
    • 3

    (1.1.2)CPU名称

    通过wmic指令查看CPU的名称,因为结果第一行是标题,所以查找不看包含标题Name的一行。
    PS:假设CPU的名字里面有Name那就看不到了……有这种名字么……?
    同理可以查询其它CPU参数信息(比如多少核),或其它硬件信息,这里不再赘述。

    C:\>wmic cpu get name | find /V /I "Name"
    12th Gen Intel(R) Core(TM) i9-12900F
    
    
    • 1
    • 2
    • 3

    (1.2)Linux

    (1.2.1)操作系统名称版本

    通过查看/etc/os-release里的好听的名字,可以看到发行版名称和版本。
    然后uname -r查看Linux的内核版本。

    [shion@homewsl ~]$ cat /etc/os-release | grep PRETTY | cut -d '"' -f 2
    Ubuntu 22.04.1 LTS
    
    [shion@homewsl /]$ uname -r
    5.15.74.2-microsoft-standard-WSL2
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (1.2.2)CPU名称

    通过查看/proc/cpuinfo里的model name,得到CPU名称。
    然后去掉重复(每个核心都有一份重复的CPU名称)。
    然后取这行冒号:后面的名称,
    并去掉名称前面的空格。

    [shion@homewsl ~]$ cat /proc/cpuinfo |grep 'model name'|uniq | cut -d ':' -f 2 | sed 's/^[ ]*//g'
    12th Gen Intel(R) Core(TM) i9-12900F
    
    
    • 1
    • 2
    • 3

    (1.3)实测

    • Microsoft Windows [版本 10.0.22621.900]
    • Ubuntu 22.04.1 LTS 5.15.74.2-microsoft-standard-WSL2
    • Anolis OS 7.9 3.10.0-1160.80.1.0.1.an7.x86_64
    • openEuler 22.03 LTS 5.10.0-60.68.0.93.oe2203.x86_64
    • CentOS Linux7 (Core) 3.10.0-1160.71.1.el7.x86_64
    • ……

    (二)程序调用命令行

    • ⚠️ 在Windows下如果要执行ver指令,需要在cmd.exe当中执行(因为ver不是一个单独的程序)。
      所以上面例子指令改为:cmd.exe /C ver
    • ⚠️ 在Windows下执行执行如果加上管道,似乎没法返回结果。Windows真麻烦……

    (2.1)Golang

    💡 其实go可以用runtime.GOOS来取得操作系统名称,但是……太简化了。
    💡 注意执行指令的时候,程序和参数别用单个字符串传进去,程序名称和每个参数分别传递。

    用法为:out, err := getCmdResult("cmd.exe", "/C", "ver")

    func getCmdResult(aCMD string, arg ...string) (string, error) {
    	var cmdText string
    	out, err := exec.Command(aCMD, arg...).Output()
    	if err != nil {
    		return "", err
    	}
    	if OSisWin() {
    		// the Windows is default GBK in Chinese, need to be decoded to UTF8.
    		b, err := simplifiedchinese.GBK.NewDecoder().Bytes(out)
    		if err != nil && err != io.EOF {
    			return "", err
    		}
    		buffer2 := bytes.NewBuffer(b)
    		cmdText = buffer2.String()
    	} else {
    		cmdText = string(out)
    	}
    	return strings.TrimSpace(cmdText), nil
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    (2.2)Java

    💡 同样Java也可以用System.getProperty("os.name")来取得操作系统名称……
    💡 执行指令和go相反,把指令全部传进去就可以了。

    用法为:out = getCmdResult("cmd.exe /C ver",Charset.forName("GBK"))

        public static String getCmdResult(String aCMD,Charset cs) throws Exception {
            Runtime r = Runtime.getRuntime();
            Process proc = r.exec(aCMD);
            BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream(), cs));
            String line;
            StringBuilder sb = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                sb.append(line).append("\n");
            }
            proc.waitFor();
            return sb.toString();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    (2.3)C++

    💡 也可以参考《关于Windows环境下处理.tar.gz文件的问题》里那样CreateProcess的方法。
    下面明显简单点(是否能在Windows服务程序中使用就不知道了)。
    呃,如果纯C请别用string。

    std::string getCmdResult(const string& strCmd)
    {
    	char buf[65535] = { 0 };
    #if defined(_MYLINUX)
    	FILE* pf = popen(strCmd.c_str(), "r");
    	if (pf == NULL) return "";
    #elif defined(_MYWINDOWS)
    	FILE* pf = _popen(strCmd.c_str(), "r");
    	if (pf == NULL)	return "";
    #endif
    
    	string strResult = "";
    	while (fgets(buf, sizeof buf, pf))
    	{
    		strResult += buf;
    	}
    #if defined(_MYLINUX)
    	pclose(pf);
    #elif defined(_MYWINDOWS)
    	_pclose(pf);
    #endif
    
    	return strResult;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    (2.4)Pascal

    (2.4.1)Lazarus - Free Pascal

    💡 如果不wait,有时还没读到调用的命令行返回就过去了。
    💡 参数需要单独添加到参数列表,这里为了方便传进去时用空格分割。
    💡 不像go或java,现在需要自己区分Windows和Linux了。

    function getCmdResult(const ACmd: string; const Params:string ='';const aWait:Integer=0): string;
    var
      {$IFDEF MSWINDOWS}
        Process: TProcess;
        AStringList: TStringList;
        AParamList: TStringList;
        i:Integer;
      {$ENDIF}
      {$IFDEF LINUX}
        t: Text;
        s: string;
      {$ENDIF}
    begin
      Result := '';
      {$IFDEF MSWINDOWS}
      Process := TProcess.Create(nil);
      try
        Process.Options := Process.Options + [poNoConsole, poUsePipes];
        Process.Executable := ACmd;
        AParamList := TStringList.Create;
        StrToStrings(Params, ' ', AParamList, False);
        Process.Parameters.Clear;
        for i := 0 to AParamList.Count -1 do
        begin
          Process.Parameters.Add(AParamList[i]);
        end;
        Process.Execute;
        if aWait>0 then
           Process.WaitOnExit(aWait);
        AStringList := TStringList.Create;
        AStringList.LoadFromStream(Process.Output);
        Result := CP936ToUTF8(AStringList.Text.Trim);
        AStringList.Free;
        AParamList.Free;
      finally
        Process.Free;
      end;
      {$ENDIF }
      {$IFDEF LINUX}
      popen(t, ACmd, 'R');
      if not Eof(t) then
      begin
        Readln(t, s);
        result:=s.Trim;
      end;
      pclose(t);
      {$ENDIF }
    end;  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    (2.4.2)Delphi

    💡 没想到最快速的开发工具确是最麻烦的。
    💡 当然是可以用TOSVersion.ToString来取得操作系统名称的……

    因为方式差太多,所以Windows/Linux分开写了:

    {$IFDEF MSWINDOWS}
    function getCmdResult(Command: string): string;
    var
      SA: TSecurityAttributes;
      SI: StartupInfo;
      PI: PROCESS_INFORMATION;
      MainRead, ChildWrite: THandle;
      WasOK: Boolean;
      Buffer: array[0..255] of AnsiChar;
      BytesRead: Cardinal;
    begin
      Result := '';
    
      SA.nLength := sizeof( SECURITY_ATTRIBUTES );
      SA.lpSecurityDescriptor := nil;
      SA.bInheritHandle := TRUE;
    
      if ( not CreatePipe( MainRead, ChildWrite, @SA, 0 ) ) then
      begin
        raise( Exception.Create('CreatePipe MRCW!'));
      end;
    
      ZeroMemory( @SI, sizeof( STARTUPINFO ) );
      SI.cb := sizeof( STARTUPINFO );
      SI.wShowWindow := SW_HIDE;
      SI.hStdError := ChildWrite;
      SI.hStdOutput := ChildWrite;
      SI.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
    
      ZeroMemory( @PI, sizeof( PROCESS_INFORMATION ) );
      if not CreateProcess(nil, PChar(@Command[1]), nil, nil, True, NORMAL_PRIORITY_CLASS , nil, nil, SI, PI) then
      begin
        CloseHandle( PI.hThread );
        CloseHandle( PI.hProcess );
        CloseHandle( MainRead );
        CloseHandle( ChildWrite);
        raise( Exception.Create('Error create process!'));
      end
      else
      begin
        CloseHandle( PI.hThread );
        CloseHandle( PI.hProcess );
        CloseHandle( ChildWrite);
      end;
    
      repeat
        WasOK := ReadFile(MainRead, Buffer, 255, BytesRead, nil);
        if BytesRead > 0 then
        begin
          Buffer[BytesRead] := #0;
          Result := Result + String(AnsiString(Buffer));
        end;
      until not WasOK or (BytesRead = 0);
      WaitForSingleObject(PI.hProcess, 1000);
      CloseHandle(MainRead);
    
    end;
    {$ENDIF}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    然后是Linux:

    {$IFDEF LINUX}
    uses
          Posix.Base,
          Posix.Unistd,
          Posix.Fcntl,
    
    ......
    ......
    
    type
      TStreamHandle = pointer;
      function popen(const command: PAnsiChar; const _type: PAnsiChar): TStreamHandle; cdecl; external libc name _PU + 'popen';
      function pclose(filehandle: TStreamHandle): int32; cdecl; external libc name _PU + 'pclose';
      function fgets(buffer: pointer; size: int32; Stream: TStreamHAndle): pointer; cdecl; external libc name _PU + 'fgets';
    
    function getCmdResult(Command: string): string;
    var
      Handle: TStreamHandle;
      Data: array[0..511] of uint8;
      acommand : PAnsiChar;
      sReturn : string;
    begin
      Result := '';
      try
        acommand := PAnsiChar(AnsiString(command));
        Handle := popen(acommand, 'r');
        sReturn := '';
        try
          while fgets(@Data[0], Sizeof(Data), Handle) <> nil do
            sReturn := sReturn + Utf8ToString(@Data[0]);
        finally
          pclose(Handle);
        end;
        Result := sReturn;
      except
      end;
    end;
    {$ENDIF}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    简直累sker人呀……

    (2.5)Python

    💡 其实Python可以用platform.platform()来取得操作系统名称……
    取得的名称还算正常,只是仍然摆脱不了“Win11版本号是10”这种bug。
    使用上Python可能是最简单的,而且Windows下可以用管道符号。
    简化到都不用自己再封装函数。

    import subprocess
    ...
    # Windows
    out = subprocess.check_output('wmic os get Caption | find /V /I "Caption"', shell=True).decode().strip()
    # or Linux
    out = subprocess.check_output('cat /proc/cpuinfo | grep \'model name\' | uniq | cut -d\':\' -f 2', shell=True).decode().strip()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    .NET Core HttpReports 监控
    YOLOv8推理详解及部署实现
    asp毕业设计——基于asp+access的网页设计辅导系统设计与实现(毕业论文+程序源码)——网页设计辅导系统
    linux高级篇基础理论五(用户安全,口令设置,JR暴力破解用户密码,NMAP端口扫描)
    两日总结十
    Vue 简单快速入门
    C- 动态链接
    unity VR Interaction Framework 创建新手势
    Vue3路由的使用
    桶装水订水小程序app,线上预约订水更便捷
  • 原文地址:https://blog.csdn.net/ddrfan/article/details/128208057