【问题标题】:execvp() - unsupported SysV optionexecvp() - 不支持的 SysV 选项
【发布时间】:2018-08-16 06:02:29
【问题描述】:

我正在尝试用 C 语言编写一个简单的 shell,它接收一个命令并使用一个子进程来执行该命令。例如,如果我输入:

ps -ael  

我的子进程应该执行该命令及其参数。我打印出我的命令,因为它们存储在一个数组中。这是我所看到的:

Array[0] = ps
Array[1] = -ael  
Array[2] = NULL

当我执行时,我得到这个:

error: unsupported SysV option

Usage:
 ps [options]

 Try 'ps --help <simple|list|output|threads|misc|all>'
  or 'ps --help <s|l|o|t|m|a>'
 for additional help text.

For more details see ps(1). 

我的代码如下。

int main(void)
{
    char *args[MAX_LINE/2 +1]; // command line arguments
    char *cmdLine;
    int should_run = 1; // flag to determine when to exit the program
    int i, x;


    printf("osh> ");
    fflush(stdout);
    fgets(cmdLine, MAX_LINE, stdin);


    char *token = strtok(cmdLine, " ");
    int position = 0;
    while (token != NULL)
    {
        args[position++] = token;
        token = strtok(NULL, " ");
    }
    i = 0;
    while (args[i] != NULL)
    {
        printf("Array[%d] = %s\n", i, args[i]);
        i++;
    }
    if (args[i] == NULL) printf("Array[%d] = NULL", i);
    x = 0;
    pid_t pid;

    /* fork a child process*/
    pid = fork();

    if (pid < 0)
    {
        /*Error occured*/
        fprintf(stderr, "Fork failed.");
        return 1;
    }
    else if (pid == 0)
    {
        /*child process*/

        execvp(args[0], args); //error here
    }
    else
    {
        /*Parent process*/

        wait(NULL);

        printf("\nChild complete\n");
    }

}

【问题讨论】:

  • @Barmar Ubuntu 16.04
  • strace -f -eexecve your-prog 运行它,看看它到底发生了什么。并检查是否包含隐藏空格(例如 print Array.. . = '%s'
  • fgets() 函数输入所有内容,包括“\n”(或缓冲区几乎已满),然后附加一个 NUL 字节。发布的代码需要将 '\n' 替换为 NUL 字节。否则,“\n”是放在args[] 中的参数的一部分,这就是出现错误消息的原因。
  • 关于:fgets(cmdLine, MAX_LINE, stdin);char *cmdLine; fgets() 函数的第一个参数预计是指向数组/缓冲区的指针,以接收读取的数据。 cmdLine 被声明为“未初始化的指针”。 IE。该指针包含堆栈中cmdLine 位置上的垃圾。这会导致未定义的行为,并可能导致段错误事件。建议:char cmdLine[ MAX_LINE ];
  • 贴出的代码无法编译!除其他外,它缺少所需的#include 语句并且缺少MAX_LINE 的定义您是否希望我们了解您的想法,包括哪个头文件以及您为MAX_LINE 定义了什么值?

标签: c shell execvp sysv


【解决方案1】:

fgets() 返回的字符串包含换行符,但您不会将其从字符串中删除。所以你将args[1] 设置为"-ael\n",而\n 不是一个有效的选项。

strtok() 分隔符中包含换行符:

char *token = strtok(cmdLine, " \n");
int position = 0;
while (token != NULL)
{
    args[position++] = token;
    token = strtok(NULL, " \n");
}

然后它不会包含在令牌中。

你应该能够在你的输出中看到这个,我敢打赌它打印出来了:

Array[0] = ps
Array[1] = -ael  

Array[2] = NULL

那里有一个空行。

顺便说一句,我看不出您将最后一个参数设置为 NULL 的位置。当strtok() 返回NULLwhile 循环停止,因此它永远不会将该结果分配给args[position++]。您需要添加:

args[position] = NULL;

在循环之后。

并且没有必要 if (args[i] == NULL) -- 之前的循环在满足该条件时停止,因此它保证为真。

【讨论】:

  • 非常感谢,成功了!我有一种感觉,它与空白空间有关..
  • 此答案未提及已发布代码中未定义行为的两个实例。
  • @user3629249 我提到了丢失的空指针,但我没有检查所有代码,我只是在寻找错误消息的原因。
  • 缺少的#define#include大概是因为他没有将它们复制到问题中。
  • 当发布的代码不是 minimal reproducible example 时,stackoverflow.com 上关于运行时问题的那些问题是“离题”。由于缺少部分而无法编译的代码不符合要求
猜你喜欢
  • 2021-10-25
  • 2018-06-10
  • 1970-01-01
  • 1970-01-01
  • 2023-02-24
  • 2018-05-19
  • 2021-12-21
  • 2021-09-25
  • 2021-10-27
相关资源
最近更新 更多