4

我正在 ubuntu 上编写一个 UNIX minishell,并尝试在此时添加内置命令。当它不是内置命令时,我 fork 然后子执行它,但是对于内置命令,我将在当前进程中执行它。

因此,我需要一种方法来查看文件是否存在(如果存在,则不是内置命令),但是 execvp 使用环境 PATH 变量自动查找它们,所以我不知道如何事先手动检查。

那么,你们知道我如何通过提供名称来测试参数以查看它是否是内置命令吗?

多谢你们。

4

4 回答 4

3

我已经测试了汤姆的答案

它包含许多问题。我在这里修复了它们并提供了一个测试程序。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>

int is_file(const char* path) {
    struct stat buf;
    stat(path, &buf);
    return S_ISREG(buf.st_mode);
}

/*
 * returns non-zero if the file is a file in the system path, and executable
 */
int is_executable_in_path(char *name)
{
    char *path = getenv("PATH");
    char *item = NULL;
    int found  = 0;

    if (!path) 
        return 0;
    path = strdup(path);

    char real_path[4096]; // or PATH_MAX or something smarter
    for (item = strtok(path, ":"); (!found) && item; item = strtok(NULL, ":"))
    {
        sprintf(real_path, "%s/%s", item, name);
        // printf("Testing %s\n", real_path);
        if ( is_file(real_path) && !(
               access(real_path, F_OK) 
            || access(real_path, X_OK))) // check if the file exists and is executable
        {
            found = 1;
        }
    }

    free(path);
    return found;
}

int main()
{
    if (is_executable_in_path("."))
        puts(". is executable");
    if (is_executable_in_path("echo"))
        puts("echo is executable");
}

笔记

  1. 返回值的测试access被颠倒了
  2. 第二个 strtok 调用有错误的分隔符
  3. strtok 改变了path论点。我的示例使用副本
  4. 没有什么可以保证连接中的正确路径分隔符 charreal_path
  5. 没有检查匹配的文件是否实际上是一个文件(目录也可以是“可执行的”)。这会导致奇怪的事情,比如.被识别为外部二进制文件
于 2012-10-07T00:52:40.847 回答
1

您可以遍历 PATH 目录,并且对于 PATH 中的每个条目(您必须将 PATH 与:,可能使用strtok分开)在每个路径的末尾连接调用的命令的名称。创建此路径后,请检查文件是否存在以及是否可以使用access执行。

int is_built_in(char *path, char *name)
{
  char *item = strtok(path, ":");

  do {
    char real_path[4096] = strcat(item, name); // you would normally alloc exactly the size needed but lets stick to it for the sake of the example
    if (!access(real_path, F_OK) && !access(real_path, X_OK)) // check if the file exists and is executable
      return 0;
  } while ((item = strtok(NULL, ":")) != NULL);
  return 1;
}
于 2012-10-07T00:21:40.433 回答
1

您可以做的是您可以更改特定目录的路径,然后使用#include<dirent.h>头文件及其readdirscandir函数遍历目录或stat结构以查看该文件是否存在于目录中。

于 2012-10-07T00:53:51.893 回答
1

为什么要在调用之前execvp进行测试?那是错误的做法。只要打电话execvp,它会告诉你程序是否不存在。

于 2012-10-07T03:40:05.380 回答