C语言 使用带有 execvp 的此处文档



我正在尝试使用 execvp 运行命令" wc -l << END",所以我正在解析命令并使用"wc -l"运行 execvp,但随后它进入无限循环。
如何使其工作,以便在找到关键字时停止(在本例中为 END)?

  • 我必须使用 execvp
  • 该命令来自用户输入,在本例中为" wc -l << END

编辑
这是我的代码(不会有太大帮助,但可以提供一些背景)[here-doc 的代码在最后一个 else 语句中]:

redirect(int proc, char * input){
    char * comm;
    int proc2;
    int append = 0;
    if(proc == 1){ //in
        comm = strsep(&input, "<");
        proc2 = check(input);
    }
    else{ //out
        comm = strsep(&input, ">");
        proc2 = check(input);
        if(proc2 == 2){ //append
            strsep(&input, ">");
            append = 1;
        }
    }
    if(proc2 == 0 || append == 1){ //only one redirection
        if(proc == 1){ //in
            input = trim(input);
            int fd = open(input, O_RDWR);
            close(0);
            dup2(fd, 0);
            close(fd);
            comm = trim(comm);
            char ** words = parse(comm);
            if(!execvp(words[0], words)){   /*exec failed */
                exit(1);
            }
        }
        else{ //out
            input = trim(input);
            int fd;
            if(append == 0){ //create
                fd = open(input, O_CREAT | O_RDWR | O_TRUNC, 
                    S_IRUSR | S_IWUSR);
            }
            else{ //append
                fd = open(input, O_CREAT | O_RDWR | O_APPEND, 
                    S_IRUSR | S_IWUSR);
            }
            dup2(fd, 1);
            close(fd);
            comm = trim(comm);
            char ** words = parse(comm);
            if(!execvp(words[0], words)){   /*exec failed */
                exit(1);
            }
        }
    }
    else{ //more than one redirection/pipe
        if(proc == proc2){ //here-doc
            strsep(&input, "<");
            input = trim(input);
        }
    }
}

一种解决方案是将用户输入存储到临时文件中,然后将临时文件作为 stdin 传递,但我想知道是否有更好的方法可以做到这一点。

无需

使用临时文件并将子进程的 stdin 指向该文件,而是可以通过管道将输入从父进程或其他子进程提供给子进程。 然后,父进程或第二个子进程将负责读取输入,监视输入标记的末尾,并将数据传递到(原始)子进程。

下面的示例演示如何使用管道和第二个子进程读取 stdin,监视输入结束标记,并将输入传递到原始子进程,直到找到它。 该示例省略了错误检查(应添加),并对要运行的命令和输入标记的末尾使用硬编码值。 请注意,在父管道中关闭管道的写入端非常重要,这样命令才能在输入读取器退出后看到它的 stdin 关闭。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
int main(int argc, char *argv[])
{
  pid_t rdr,  /* input reader process */
        cmd,  /* command runner process */
        wres; /* wait() result */
  /* pipe for passing input from rdr to cmd */
  int pipefd[2] = {0};
  /* command and args to pass to execvp() */
  char *command = "wc";
  char *cmdargs[] = { "wc", "-l", NULL };
  /* end of input marker */
  char *endinp = "ENDn";
  /* create a pipe: 
     - read end's fd will be pipefd[0], 
     - write end's fd will be pipefd[1] */
  pipe(pipefd);
  cmd = fork();
  if (!cmd) {  /* COMMAND RUNNER PROCESS */
    dup2(pipefd[0],0); /* set stdin to pipe's read end */
    close(pipefd[1]);  /* close pipe's write end */
    /* exec command (will read from stdin) */
    execvp(command, cmdargs);
  }
  rdr = fork();
  if (!rdr) {   /* INPUT READER PROCESS */
    close(pipefd[0]); /* close pipe's read end */
    /* read input from stdin until a line containing only
       the end of input marker is found */
    char buf[1024];
    while (fgets(buf,sizeof(buf),stdin)) {
      /* break when end of input marker is read */
      if (!strcmp(buf,endinp)) break;
      /* write data to pipe */
      write(pipefd[1],buf,strlen(buf));
    }
    return 0;
  }
  /* PARENT PROCESS */
  close(pipefd[0]); /* close pipe's read end */
  close(pipefd[1]); /* close pipe's write end */
  /* wait for both children to exit */
  do {
    wres = wait(NULL);
    if (wres == rdr) rdr = 0;
    if (wres == cmd) cmd = 0;
  } while (rdr || cmd);
  return 0;
}

通常,您将问题与代码一起发布,否则我们将无法正确帮助您发展编程技能。这次我会给你一个小菜一碟,给你一个示例代码(这可能是完整的答案)。

#include <stdio.h>
#include <unistd.h>
#include <err.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
    pid_t pid;
    int status;

    // you must provide the full path for the executable
    // such as /bin/echo, /usr/bin/wc ...
    if(argc < 2)
    {
        printf("expected format example /usr/bin/wc -l << ENDn");
        return (-1);
    }
    // fork your process since EXEC family
    // takes control over your process
    // This way you may do other things
    if((pid = fork()) < 0)
        err(1, "fork() error");
    if(pid == 0) /* child */
    {
        // argv[0] is the name of your program executable
        // first argument to execvp is the target executable
        // with the full path, again /bin/echo
        // segund argument is a list of arguments for your
        // target null terminated. Note that the first
        // argument of that list is the name of the executable/location
        // itself
        // illustrative: execvp("/bin/echo", {"/bin/echo", "example", NULL}) 
        if(execvp(argv[1], &argv[1]) < 0)
            err(1, "execvp() error");
    }
    else /* father */
    {
        printf(">> father waiting child..n");
        while(wait(&status) != pid);
        printf(">> child finishedn");
    }
    return (0);
}

如果你想深入了解这个主题,你可以看看这个。

相关内容

  • 没有找到相关文章

最新更新