在执行 Linux 命令之前了解它是否存在的方法

Way to know if Linux command exists before executing it

本文关键字:是否 存在 方法 了解 执行 Linux 命令      更新时间:2023-10-16

我想写一个生成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命令?

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

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

寻找什么:

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

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

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

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

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

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

请注意,当被要求执行一个不存在的程序时,popen(3) 和 system(3) 都会失败(因为它们都用-c分叉(2) 一个/bin/sh shell)。因此,您不需要测试gzip是否存在,并且始终需要测试systempopen是否成功(可能由于多种原因而失败,请参阅下面的fork失败,以及其他失败的文档)。

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

在大多数 Linux 系统上,gzip通常可在/bin/gzip处获得(实际上始终安装gzip); 这是文件系统层次结构标准所要求的(该标准规定如果安装了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 标准库作为libz.so.1是必需的);你想要它的gzopengzwritegzprintfgzputsgzclose等....功能!这将更快(不需要 fork(2) 任何外部进程)和更可靠(不依赖于某些外部程序,如gzip;即使由于已达到限制而无法fork也可以工作 - 参见 setrlimit(2) 与RLIMIT_NPROCulimit内置的 bash(1))

另请参阅高级 Linux 编程