为什么在 C 中执行超过 1 个命令时 execvp() 失败?

Why does execvp() failed when executing more than 1 command in C?

我正在编写一个程序,它将从文件名 cmdfile.txt 中读取命令列表并在终端中执行它们。

cmdfile.txt 包含:

whoami
cal 4 2020
echo The time is:
date

我遇到的问题是,当文件仅包含 1 个命令行时,程序可以正常运行。但是,当文件包含多于 1 个命令行时,该命令无法执行或产生未知命令。 以下是我正在进行的工作代码:

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

void parse(char *line, char **argv)
{
     while (*line != '[=11=]') {       /* if not the end of line ....... */ 
          while (*line == ' ' || *line == '\t' || *line == '\n')
               *line++ = '[=11=]';     /* replace white spaces with 0    */
          *argv++ = line;          /* save the argument position     */
          while (*line != '[=11=]' && *line != ' ' && 
                 *line != '\t' && *line != '\n') 
               line++;             /* skip the argument until ...    */
     }
     *argv = '[=11=]';                 /* mark the end of argument list  */
}

void execute(char **argv)
{
     pid_t  pid;
     int    status;
     pid = fork();
     if (pid < 0) {     /* fork a child process           */
          perror("The error for fork() is: ");
          exit(1);
     }
     else if (pid == 0) {          /* for the child process:         */
          if (execvp(*argv, argv) < 0) {     /* execute the command  */
               perror("The error is: ");
               exit(1);
          }
     }
     else {                                  /* for the parent:      */
          while (wait(&status) != pid)       /* wait for completion  */
               ;
     }
}

void  main(void)
{
     char  line[1024];             /* the input line                 */
     char  *argv[64];              /* the command line argument      */
     bool running = 1;

     FILE *fp = fopen("cmdfile.txt", "r");
     if(fp == NULL)
     {
          perror("Unable to open file!");
          exit(1);
     }

     while (fgets(line, 1024, fp)) {                   /* repeat until done ....         */      
          strtok(line, "\n");
          parse(line, argv);       
          execute(argv);
     }
}

我的第一个猜测是因为 fgets 由于新行的分隔而没有像我预期的那样运行?我试图将行打印到终端以跟踪错误,但我不知道程序出了什么问题。谁能帮我指出我犯的错误?

上面代码运行时我的输出:

The error is: : No such file or directory
cal: not a valid year 2020
The time is:
The error is: : No such file or directory
The time is:
The error is: : No such file or directory
The error is: : No such file or directory

cmdfile.txt 文件来自 Windows 机器并被复制到 Linux 机器而不翻译行尾。因此,每一行都以 CRLF — "\r\n" 结尾。您的代码小心地将 '\n' 替换为空字节,但会在字符串中留下 '\r' 。当你将 "whoami\r" 传递给 execvp() 时,它找不到命令;它会找到 "whoami" 而不是另一个。 cal 似乎也不喜欢以 \r 结尾的数字。等等。 (echo 命令与 '\r' 无关。)

有很多方法可以修复它。在您的代码上下文中,最简单的方法是将 main() 循环中的 strtok() 行更改为:

strtok(line, "\r\n");

字符串中字符的顺序无关紧要。