【问题标题】:c++ - Way to know if Linux command exists before executing itc++ - 在执行之前知道 Linux 命令是否存在的方法
【发布时间】:2014-01-23 09:45:04
【问题描述】:

我想写一个生成 gz 文件的函数。该功能只能在Linux 上运行,所以我想使用gzip 命令(只需执行外部命令)。
到目前为止,我有这个:

bool generate_gz( const String& path )
{
  bool res = false;

  // LINUX
#ifndef __WXMSW__

  if( !gzip_command_exists())
     cout << "cannot compress file. 'gzip' command is not available.\n";
  else
     res = (0 == execute_command(String::Format("gzip %s", path.c_str())));

  // WINDOWS
#else

  // do nothing - result will be false

#endif

  return res;
}

bool gzip_command_exists()
{
  // TBD
}

问题

有没有办法实现gzip_command_exists()?如果是这样,它是否必须涉及运行(或尝试运行)gzip 命令?

【问题讨论】:

  • 有办法,但没必要。无论如何,您必须检查运行的结果。只需尝试运行命令并报告任何失败。
  • 运行命令的退出代码是否告诉我它是否存在并且在进程中失败,或者根本不存在?我想区分这些失败。
  • 尝试man execve 并查看错误描述。 (您可能应该使用exec 系列之一,而不是system)。
  • 随意告诉我在这个问题中究竟有什么不清楚或没有用的,值得一票否决。这样我就可以改进它。
  • 我对这个问题投了反对票,因为稍微研究一下就会告诉你zlibgzopen 或者只是system(3) 可能会失败。

标签: c++ linux gzip


【解决方案1】:

最简单的就是通过system():"which gzip"执行,看看系统调用的退出码:

返回值 错误时返回的值为 -1(例如 fork(2) 失败),否则返回命令的状态。后者返回状态 在 wait(2) 中指定的格式。因此,该命令的退出代码将是 WEXITSTATUS(status)。如果 /bin/sh 不能 执行, 退出状态将是执行 exit(127) 的命令的状态。

寻找什么:

:~$ which gzip
/bin/gzip
:~$ echo $?
0
:~$ which gzip11
:~$ echo $?
1

【讨论】:

  • 有趣的是,当从后台进程运行时,这对我不起作用,例如一个守护进程。在前台进程中,结果为零;在守护进程中,结果为 -1。
【解决方案2】:

如果您不想生成外部命令,可以使用stat 函数来检查文件是否存在以及它是否可以在 POSIX 系统上执行。

如果您不想硬编码 gzip 的路径,它会稍微复杂一些。您必须获取 PATH 环境变量,将其拆分为冒号,然后检查每个路径是否有 gzip。同样,路径变量的名称和格式是 POSIX 特定的。检查 getenv 函数读取路径,你可以使用 strtok 来分割它。

但是,与只是尝试运行它并处理任何错误相比,它是否值得检查是值得怀疑的。

【讨论】:

    【解决方案3】:

    您可以使用popen(3) 来读取/usr/bin/which gzip 的输出(您也可以使用它通过write-popen-ing gzip &gt; file.gz 命令即时压缩)。你也可以有:FILE* pgzipv = popen("gzip --version", "r");fgets第一行然后pclose....

    您可以考虑使用getenv("PATH"),然后在其上使用access 测试对通过将/gzip 附加到PATH 中的每个元素等获得的每个构造路径进行循环...您可以也 fork 然后 execvp 使用 gzip --versionstdoutstderr 适当重定向,等等。

    请注意,popen(3)system(3) 在被要求执行不存在的程序时都会失败(因为它们都是 fork(2) /bin/sh shell 和 -c)。所以你不需要测试gzip的存在,你总是需要测试systempopen的成功(可能失败的原因有很多,见下文fork失败,以及文档其他故障)。

    为了挑剔,检查gzip 是否存在是没有用的:它[文件/bin/gzip] 可能(不太可能)已在您的检查之间被删除-例如使用access 如下或popen 如上所述-以及您以后调用systempopen;所以你第一次检查gzip 不要带任何东西。

    在大多数 Linux 系统上,gzip 通常在/bin/gzip 可用(实际上总是安装gzip); 这是file system hierarchy standard 所要求的(它表示如果安装了gzip,它应该在该文件路径中)。然后你可以使用access(2) 例如像

    这样的代码
    #define GZIP_PATH "/bin/gzip" /* per FSH, see www.pathname.com/fhs */
    if (access(GZIP_PATH, X_OK)) { perror(GZIP_PATH); exit(EXIT_FAILURE); };
    

    最后,您根本不需要派生一个gzip 进程来gzip-压缩文件。你可以(而且你应该)简单地使用像zlib这样的库(根据Linux Standard Base作为libz.so.1,这是必需的);你想要它的gzopengzwritegzprintfgzputsgzclose 等......功能!这会更快(无需fork(2) 任何外部进程)和更可靠(不依赖于某些外部程序,如gzip;即使fork 因已达到限制而无法使用也可以工作 - 请参阅setrlimit(2)带有RLIMIT_NPROCulimit 内置的bash(1))

    另见Advanced Linux Programming

    【讨论】:

    • 感谢您的建议。似乎我通过使用 zlib 来增加实现的复杂性。我想了解通过使用 zlib 而不是激活 99% 的时间可用的外部命令可以获得什么?
    • 使用 zlib(在我听说的每个 Linux 系统上都可用并安装),您无需依赖外部资源。因此,通过使用 zlib,您可以降低软件的复杂性!
    猜你喜欢
    • 1970-01-01
    • 2014-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 2017-09-18
    相关资源
    最近更新 更多