【问题标题】:Execlp() not taking parameter list, just the command. UNIX/LINUX programmingExeclp() 不带参数列表,只带命令。 UNIX/LINUX 编程
【发布时间】:2019-12-07 17:16:44
【问题描述】:

我正在尝试创建一个 microshell。它读入命令,解析它并拆分它,然后执行。要解析,首先我用分隔符 || 分隔,如果有管道,最多可以得到两个命令。将每个命令拆分成一个字符串数组。

我认为这就是execlp 的工作方式,但它只运行命令,即使 C 字符串“cmd1”确实包含参数。有人可以帮我理解我是如何将错误的参数传递给execlp 函数的吗?

shell.h

   /****************************************************************
   PROGRAM:   MicroShell(assignment 4)
   FILE:      shell.h

   AUTHOR:    Nick Schuck

   FUNCTION:  This contains the header for the shell class   
   ****************************************************************/
   #ifndef _shell_h
   #define _shell_h

   #include <sys/types.h>
   #include <unistd.h>  
   #include <cstdio>
   #include <pwd.h>
   #include <cstring>
   #include <sys/wait.h>
   #include <cstdlib>
   #include <vector>


   class Shell
   {
        private:
        char buffer[1024];
        const char *cmd1[10];
        const char *cmd2[10];

        public:
        Shell();  //default constructor
        void askForCommand(); 
        void readCommandLine();
        void parseBuffer();
        void invokeCommand();
        void executeOneCommand();
        void executeTwoCommands();
        };

        #endif 

shell.cc

     /***************************************************************
         PROGRAM:   MicroShell(assignment 4)
         FILE:      shell.c

   AUTHOR:    Nick Schuck

   FUNCTION:  This file contains the implementation of 
              class shell from file "shell.h"
****************************************************************/
#include "shell.h"
#include <iostream>


Shell::Shell()
{
    /**Get current user*/
    struct passwd *p = getpwuid(getuid());
    if (!p) //Error handling
        puts("Welcome to Nick Schuck's MicroShell, Anonymous");

    /**Welcome message for my shell*/
    printf("\n\nWelcome to Nick Schuck's Microshell, user %s!\n\n", p->pw_name);
}


void Shell::askForCommand()
{
    /**Command Prompt*/
    printf("myshell>");
}


void Shell::readCommandLine()
{
    /**Read stdin into buffer array IF no*/
    /**errors occur                      */
    if (fgets(this->buffer, 1024, stdin) != NULL)
    {
        this->buffer[strlen(this->buffer) - 1] = 0;
    }
}


void Shell::parseBuffer()
{
    /**Variables*/
    int i = 0, u = 0,
        t = 0;
    char *ptr;  
    char parsingBuffer[2][512];


    /**Parse buffer for multiple commands*/
    strcpy(parsingBuffer[0], strtok(this->buffer, "||"));
    while ((ptr = strtok(NULL, "||")) != NULL)
    {
        i++;
        strcpy(parsingBuffer[i], ptr);
    }


    //**Get first command*/
    this->cmd1[0] = strtok(parsingBuffer[0], " ");
    while ((ptr = strtok(NULL, " ")) != NULL)
    {
        u++;
        this->cmd1[u] = ptr;
        this->cmd1[u+1] = '\0';
    }

    //!!!TESTING TO SEE COMMAND ARE IN CMD1
    int b = 0;
    while(cmd1[b] != '\0')
    {
        std::cout << cmd1[b] << "\n";
        b++;
    }


    /**Get second command*/
    this->cmd2[0] = strtok(parsingBuffer[1], " ");
    while ((ptr = strtok(NULL, " ")) != NULL)
    {
        t++;
        this->cmd2[t] = ptr;
    }
}


void Shell::invokeCommand()
{
    if (this->cmd1[0] == NULL)
    {
        //do nothing
    }
    else if(this->cmd1[0] != NULL && this->cmd2[0] == NULL)
    {
        executeOneCommand();
    }
    else if(this->cmd1[0] != NULL && cmd2[0] !=NULL)
    {
        executeTwoCommands();
    }
}


void Shell::executeOneCommand()
{
    pid_t pid; //pid for fork
    int status;
    char args[512];

    if ((pid = fork()) < 0)
    {
        printf("fork error\n");
        exit(-1);
    }
    else if(pid == 0)  //Child Process
        {
            execlp(cmd1[0], *cmd1);     
        }
        else  //Parent Process
        {
            if ((pid = waitpid(pid, &status, 0)) < 0)
            {
                printf("waitpid error in main\n");
                exit(-1);
            }
        }

    }

main.cc

#include "shell.h"
#include <iostream>
#include <vector>

int main()
{
    const int BUFFER_SIZE = 1024;
    const int MAX_COMMANDS_IN_BUFFER = 2;

    /**Initialize a new shell object*/
    Shell shell;

    /**Print command prompt to screen*/
    shell.askForCommand();

    /**Read users command*/
    shell.readCommandLine();

    /**parse buffer to find individual*/
    /**commands                        */
    shell.parseBuffer();

    /**Invoke command*/
    shell.invokeCommand();
}

【问题讨论】:

标签: c++ shell unix


【解决方案1】:

你不能使用execlp()——你必须使用execvp()

execvp(cmd1[0], cmd1);

要使用execlp(),您必须在编译时知道该命令的固定参数列表——您必须能够编写:

execlp(cmd_name, arg0, arg1, …, argN, (char *)0);

您对execlp() 的调用也是错误的,因为您没有提供(char *)0 参数来指示参数列表的结尾。

您的代码还需要处理 exec*() 返回,这意味着命令失败。通常这意味着它应该打印一条错误消息(该命令未找到,或权限被拒绝等),然后以适当的非零错误状态退出。

【讨论】:

  • 当我尝试 Execvp() 时,它说不能从 const char* 更改为 char *const。我理解指针(据我所知),但我不明白如何让它工作。我已经查看了所有论坛,但是什么时候做一些对这些问题有用的事情,它从来没有用过。我将如何使用我的 c 字符串数组“cmd1” 在 execvp() 中编写参数
  • 另外,感谢您提出处理空指针错误的建议。在调用命令或执行时没有做太多的错误处理,只是想让它首先工作。你知道我能不能用“cmd1”的当前格式调用Execvp
  • 从类中的类型中删除常量。它们是可修改的字符串,即使您通常不会修改它们。
  • 还要确保在 cmd1 中最后一个有效参数之后有一个空指针。
  • 感谢您的帮助。我想我一直在做很多事情,我现在脑子里一片混乱。
猜你喜欢
  • 2023-04-11
  • 1970-01-01
  • 1970-01-01
  • 2013-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-04
  • 2012-02-25
相关资源
最近更新 更多