【问题标题】:understanding why`execvp` works where `execv` fails理解为什么`execvp`在`execv`失败的地方工作
【发布时间】:2018-12-17 14:13:09
【问题描述】:

我被要求在 C 中实现一个“迷你外壳”。我决定使用 execv,但它不起作用,当我将其更改为 execvp 时,它起作用了!看代码(动作在tokExec函数中)

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


void tokExec(char command[128])
{
    // 'strtok' may look innocent, but it modifies the string, so I want a copy of the original command.
    char tokString[128];
    // 'strlen' is the lenghth without the null terminator.
    strncpy(tokString,command,strlen(command)+1);


    char* tokPtr = NULL;
    char tok[] = " ";
    int narg = 0;
    tokPtr = strtok(tokString,tok);
    char *myargs[64];

    while(tokPtr != NULL)
    {
            printf("arg %d is: %s\n",narg,tokPtr);
            myargs[narg] = tokPtr;
            narg = narg + 1;
            tokPtr = strtok(NULL,tok);
    }
    printf("Total number of arguments: %d\n",narg);

    // add the final 'NULL' element.
    myargs[narg] = NULL;

    execvp(myargs[0],myargs);
    printf("error\n");
    exit(1);
}

void normal()
{
    char command[128];
    strcpy(command,"default\0");
    printf("myShellZ > ");
    gets(command);
    while(strcmp(command,"exit") != 0)
    {
            int status;
            pid_t pid;
            if( (pid = fork()) == 0 )
            {
                    tokExec(command);
            }
            wait(&status);
            printf("myShellz > ");
            gets(command);
    }
}

void debug()
{
    // TO DO ....
    int a = 3;
}

// switching between shell modes: normal or debug.
int main(int argc, char* argv[])
{
    if(argc == 1)
            normal();
    else if(strcmp("-debug",argv[1]))
            debug();
    else
            exit(1);

    exit(0);
}

如果不是tokExec 末尾的execvp,我将使用execv,如果我的输入只有ls 或ps 等execv 很好,但是如果我向输入,例如:ls -l myshell.c 或 evev 只是 ls -l 或 ps aux 我得到了 error 输出。

man 几乎没有提到这些功能之间的差异,但它声称:

execv()、execvp() 和 execvpe() 函数提供了一个指向以 null 结尾的字符串的指针数组,这些字符串表示新程序可用的参数列表。首先 按照惯例,参数应该指向与正在被调用的文件关联的文件名 执行。指针数组必须以空指针终止。

总之,在这种情况下修复我的程序的execv 和execvp 之间有什么区别?我知道execv 也适用于 bash 命令,因为如果我输入不带参数的 bash 命令,它就可以工作,并且这两个函数的签名是相同的。感谢您的帮助!

【问题讨论】:

  • 你看execv和errno的返回值了吗?
  • 进一步查看“execlp() 和 execvp() 的特殊语义”下的文档,其中解释了 execlp() 的作用,execve() 的作用。
  • execv 返回int。我试过man errno,但我看不到任何返回值......无论如何与这个问题有什么关系? (让我好奇)
  • perror 给了我No such file or directory,答案中对此进行了解释,对于execv,您需要通过整个路径。
  • 喜欢/bin/ls?

标签: c exec execvp execv


【解决方案1】:

答案在手册页中。如果您在引用的部分之后阅读该部分,它会谈到差异

execlp()、execvp() 和 execvpe() 函数复制操作 的 如果指定的文件名不存在,shell 会搜索可执行文件 包含斜杠 (/) 字符。在冒号分隔的文件中查找文件 在 PATH 环境变量中指定的目录路径名列表。如果 此变量未定义,路径列表默认为当前目录 后面是 confstr(_CS_PATH) 返回的目录列表。 (这 confstr(3) 调用通常返回值“/bin:/usr/bin”。)

【讨论】:

  • 好吧,但为什么它不适用于execv?为什么如果我只发送命令本身,它甚至对execv 也有效?
  • 因为execv 不执行上述操作 - 它需要可执行文件的完整或相对路径
  • @ZENir 如果您告诉 execvp() 运行“ls”命令,它将搜索您的 PATH,通常是 /bin/ /usr/bin/ /sbin/ 等等,并且尝试找到“ls”命令的可执行文件并运行它。如果您告诉 execv() 运行“ls”命令,它不会查看 PATH,它将尝试运行当前目录中的“ls”可执行文件 - 除非您将目录更改为 /usr,否则该可执行文件不存在/bin/
  • @ChrisTurner 所以如果我将//bin/ 连接到args[0] 你声称execv 将适用于位于bin 目录中的所有bash 命令?
  • 当然,但你最好使用execvp,这样你就不必重新实现你的shell需要的路径搜索功能
猜你喜欢
  • 2010-09-15
  • 2012-10-22
  • 1970-01-01
  • 2020-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多