为什么在 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");
字符串中字符的顺序无关紧要。
我正在编写一个程序,它将从文件名 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");
字符串中字符的顺序无关紧要。