【问题标题】:C++ get linux distribution name\versionC++ 获取 linux 发行版名称\版本
【发布时间】:2011-09-13 00:38:24
【问题描述】:

根据问题“How to get Linux distribution name and version?”,获取 linux 发行版名称和版本,这是可行的:

lsb_release -a

在我的系统上,它显示了所需的输出:

No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 9.10
Release:    9.10
Codename:   karmic

现在,要在 C++ 中获取此信息,Qt4 的 QProcess 将是一个不错的选择,但由于我在没有 Qt 的情况下使用 std c++ 进行开发,我需要知道如何在标准 C++ 中获取此信息,即过程的标准输出,也是一种解析信息的方法。

到目前为止,我正在尝试使用来自 here 的代码,但我被困在函数 read() 上。

【问题讨论】:

  • 您遇到了什么问题?从 C++ 启动外部进程?读取它的输出? ...请更具体,并展示您到目前为止所拥有的内容。
  • 请注意,并非所有系统都默认安装 lsb_release。有些(如 CentOS 7)需要显式安装。
  • Fedora 31 的发布版本在 /etc/redhat-release

标签: c++ linux distribution


【解决方案1】:

你可以简单地使用函数:

int uname(struct utsname *buf);

通过包含标题

#include <sys/utsname.h>

它已经将名称和版本作为结构的一部分返回:

   struct utsname 
   {
       char sysname[];    /* Operating system name (e.g., "Linux") */
       char nodename[];   /* Name within "some implementation-defined network" */
       char release[];    /* OS release (e.g., "2.6.28") */
       char version[];    /* OS version */
       char machine[];    /* Hardware identifier */
       #ifdef _GNU_SOURCE
          char domainname[]; /* NIS or YP domain name */
       #endif
   };

我错过了什么吗?

【讨论】:

  • 其实这已经实现了。我需要知道发行版名称和版本,例如“Ubuntu”或“Fedora”等
  • 由于我的程序只在 Ubuntu 系统上运行,结合这个答案对我有帮助:askubuntu.com/a/517140/17800
【解决方案2】:

对于最近的 linux 发行版,您可以使用以下命令获取操作系统信息。输出非常标准,可以使用以下规范进行解析:

https://www.freedesktop.org/software/systemd/man/os-release.html

cat /etc/os-release

示例输出:

NAME=Fedora
VERSION="27 (Twenty Seven)"
ID=fedora
VERSION_ID=27
PRETTY_NAME="Fedora 27 (Twenty Seven)"

NAME="Ubuntu"
VERSION="16.04.4 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.4 LTS"
VERSION_ID="16.04"

NAME="Arch Linux"
PRETTY_NAME="Arch Linux"
ID=arch
ID_LIKE=archlinux
ANSI_COLOR="0;36"

【讨论】:

    【解决方案3】:

    从 cplusplus.com 论坛获得,一个简单的电话 GetSystemOutput("/usr/bin/lsb_release -a") 就可以了。

    char* GetSystemOutput(char* cmd){
            int buff_size = 32;
        char* buff = new char[buff_size];
    
            char* ret = NULL;
            string str = "";
    
        int fd[2];
        int old_fd[3];
        pipe(fd);
    
    
            old_fd[0] = dup(STDIN_FILENO);
            old_fd[1] = dup(STDOUT_FILENO);
            old_fd[2] = dup(STDERR_FILENO);
    
            int pid = fork();
            switch(pid){
                    case 0:
                            close(fd[0]);
                            close(STDOUT_FILENO);
                            close(STDERR_FILENO);
                            dup2(fd[1], STDOUT_FILENO);
                            dup2(fd[1], STDERR_FILENO);
                            system(cmd);
                            //execlp((const char*)cmd, cmd,0);
                            close (fd[1]);
                            exit(0);
                            break;
                    case -1:
                            cerr << "GetSystemOutput/fork() error\n" << endl;
                            exit(1);
                    default:
                            close(fd[1]);
                            dup2(fd[0], STDIN_FILENO);
    
                            int rc = 1;
                            while (rc > 0){
                                    rc = read(fd[0], buff, buff_size);
                                    str.append(buff, rc);
                                    //memset(buff, 0, buff_size);
                            }
    
                            ret = new char [strlen((char*)str.c_str())];
    
                            strcpy(ret, (char*)str.c_str());
    
                            waitpid(pid, NULL, 0);
                            close(fd[0]);
            }
    
            dup2(STDIN_FILENO, old_fd[0]);
            dup2(STDOUT_FILENO, old_fd[1]);
            dup2(STDERR_FILENO, old_fd[2]);
    
        return ret;
    }
    

    【讨论】:

    • 有一半的时间这不起作用,它只是挂起。知道为什么吗?另外,“buff”不是内存泄漏,因为您从未释放它吗?
    【解决方案4】:
    int writepipe[2];
    if (pipe(writepipe) < 0) {
      perror("pipe");
      return 1;
    }
    int ret = fork();
    if (ret < 0) {
      perror("fork");
      return 1;
    }
    else if (ret == 0) // child process
    {
      dup2(writepipe[1],1); // set writepipe[1] as stdout
      // close fds
      close(writepipe[0]);
      close(writepipe[1]);
      execlp("lsb_release","lsb_release","-a",NULL); //TODO: Error checking
    }
    else // parent process
    {
      int status;
      waitpid(ret,&status,0); //TODO: Error checking
      //do what you need
      //read output of lsb_release from writepipe[0]
    }
    

    对我有用

    【讨论】:

    • 如何从 writepipe 读取 lsb_release 的输出? Writepipe 是一个非常小的缓冲区,如果您的意思是写入并从中获取返回,您就不会认真。
    【解决方案5】:

    有名为 /etc/version 和 /etc/release 的文件包含您使用的是 Ubuntu 还是 Fedora 等信息(这就是OP 澄清了他的问题)。

    【讨论】:

    • 我使用的是 Ubuntu 12,这些文件不存在。因此,如果它不是 Linux 的可移植解决方案,这似乎不是一个好的选择。
    • 我找到了/etc/lsb-release/etc/debian_version,很有趣。我会把这个添加到答案中。
    【解决方案6】:

    我个人喜欢 @Alok Slav 发布的 uname 解决方案,但如果它可以帮助需要使用命令行实用程序获取信息的人,请考虑使用 popen

    【讨论】:

    • 不起作用.. uname 在我的 Debian linux 系统上返回“Linux”。我想要“Debian”;或“Ubuntu”。或“红帽”等。
    • @RobinDavies 看起来您在评论错误的答案。 'uname' 答案在上面。
    • 我在评论你个人喜欢一个没有解决 OP 问题的答案,所以没有人需要浪费时间关注链接。 Alok 的回答已被标记为错误。 . ;-) 没有伤害没有犯规..
    • @RobinDavies 它适用于 Debian 9:$ uname -a Linux debian9-zb17m2 4.9.0-11-amd64 #1 SMP Debian 4.9.189-3+deb9u2 (2019-11-11) x86_64 GNU/Linux
    猜你喜欢
    • 2012-10-17
    • 2015-01-07
    • 1970-01-01
    • 2011-02-14
    • 1970-01-01
    • 2011-12-11
    • 2013-02-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多