【问题标题】:Execvp linux: trying to make my shell work in CExecvp linux:试图让我的 shell 在 C 中工作
【发布时间】:2021-05-03 16:00:23
【问题描述】:

我正在尝试制作简单的外壳,但在特定条件下,我必须使用以下结构:

typedef  struct cmd_struct{
  char cmd[80];
  char args[10][80];
  int nargs;
} cmd_type;

cmd里面我会把de main命令和参数保存在args中。

然后我从一个文件中读取不同的命令,并将它们保存到 cmd_type 的数组中。我的程序或假外壳,要求一个数字,并应该从这个数组中获取它。

我执行命令的函数如下所示:

void execCmd(cmd_type* cmds_arg, int idxCmd){
  pid_t pid;
    printf("Father: my pid is %d\n", getpid());
    char* buff;
    pid = fork();
    if (pid == 0) {  
        printf("Child process: My pid is %d\n", getpid());
           printf("-------------- Child doing exec: %s\n", cmds_arg[idxCmd].cmd);
           execvp(cmds_arg[idxCmd].cmd,&cmds_arg[idxCmd].args);
           _exit(2);
        _exit(1);
    } 
    printf("Father: Gonna wait for Child\n");

    int status;
    wait(&status);
    printf("-------------- Father: Child finished\n");

    // WIFEXITED, WEXITSTATUS Macro of the gnu lib POSIX standard to recover end status
    if ( WIFEXITED(status) ) {   
        const int es = WEXITSTATUS(status);
        printf("Father: Child Complete with exit status %d\n", es);
        if(es == 1) printf("Father: Child didn't execute any command\n");
        else if(es == 2) printf("Father: Child command was not found\n");
    }
}

如您所见,当我调用 execvp() 系统调用时,我做错了。第一个论点我认为是对的,第二个是完全错误的。

首先,我有一个转换问题,第二个问题是数组应该包含“main command”、“arg1”、“arg2”……而我的只有参数。我错了吗?

有没有办法使用 sscanf() 之类的服务添加“主命令”?最重要的是,我有机会让它这样工作吗?

【问题讨论】:

  • 你是对的,表中的第一个条目是命令名称。此外,参数表必须以 NULL 结尾:最后一个条目必须包含 NULL,因为内核需要它知道参数列表何时停止。
  • 学习sash的源码。
  • 感谢@RachidK。告诉我有关 NULL 参数的信息,我现在没有。并感谢您告诉我遵循哪种方式可以获得最终答案。

标签: c linux execvp


【解决方案1】:

使用char args[10][80];execvp(cmds_arg[idxCmd].cmd,&cmds_arg[idxCmd].args); 将不起作用(甚至无法编译),因为 execvp 需要一个指向每个参数的 const char* 指针,而您的 .args 没有没有任何指针。

这样的事情可能会奏效:

const char *p[11];  /* Contains up to 10 pointers + trailing NULL. */
cmd_type *this_cmd = &cmds_arg[idxCmd];
for (int i = 0; i < this_cmd->nargs; ++i) {
  p[i] = &this_cmd->args[i];
}
p[this_cmd->nargs] = NULL;
execvp(this_cmd->cmd, p);

【讨论】:

  • p[] 应该是 12 个指针:cmd_name,最多 10 个参数和 NULL。 p[0] 应该指向 this_cmd->cmd, p[1 to nargs] = this_cmd->args[0 to nargs - 1], p[nargs + 1] = NULL
  • @RachidK.:当然,p[0] 应该指向$0(程序名称),并且该值已经存储在this_cmd-&gt;cmd 中。但是,通过阅读问题,是否已经是这种情况并不明显。
【解决方案2】:

本着与@pts 的回答相同的精神,您可以将 execvp() 的参数复制到动态分配的表中:

void execCmd(cmd_type* cmds_arg, int idxCmd){
  pid_t pid;
  printf("Father: my pid is %d\n", getpid());
  char* buff;
  pid = fork();
  if (pid == 0) {

    int i;
    char **args = (char **)malloc((1 + cmds_arg[idxCmd].nargs + 1) * sizeof(char *));

    args[0] = cmds_arg[idxCmd].cmd;
    for (i = 1; i < (cmds_arg[idxCmd].nargs + 1); i ++) {
      args[i] = cmds_arg[idxCmd].args[i - 1];
    }
    args[i] = NULL;

    printf("Child process: My pid is %d\n", getpid());
    printf("-------------- Child doing exec: %s\n", cmds_arg[idxCmd].cmd);
    execvp(cmds_arg[idxCmd].cmd, args);
    _exit(2);
  } 
  printf("Father: Gonna wait for Child\n");

  int status;
  wait(&status);
  printf("-------------- Father: Child finished\n");

  // WIFEXITED, WEXITSTATUS Macro of the gnu lib POSIX standard to recover end status
  if ( WIFEXITED(status) ) {   
    const int es = WEXITSTATUS(status);
    printf("Father: Child Complete with exit status %d\n", es);
    if(es == 1) printf("Father: Child didn't execute any command\n");
    else if(es == 2) printf("Father: Child command was not found\n");
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-25
    • 1970-01-01
    • 2015-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多