在调用execvp之前测试文件是否存在

时间:2012-10-07 00:13:16

标签: c shell testing path execvp

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

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

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

谢谢你们。

4 个答案:

答案 0 :(得分:3)

我已经测试了Tom的答案

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

#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. 在连接的real_path
  5. 中没有任何东西可以保证正确的路径分隔符char
  6. 没有检查匹配的文件是否实际上是一个文件(目录也可以是'可执行的')。这导致奇怪的事情,如.被识别为外部二进制文件

答案 1 :(得分: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;
}

答案 2 :(得分:1)

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

答案 3 :(得分:1)

为什么要在调用execvp之前测试?这是错误的做法。只需致电execvp,它就会告诉您程序是否不存在。