为什么 getline() 获取前一行?
Why does getline() get the preceding line?
bdoetsch@Kaladin:~/Documents/School$ ./shell
Shell(pid = 6955) 1> ls
command: ls
argv[i] = ls
argv[i] = ./shell
Parent says 'child process has been forked with pid=6956'
./shell
Parent says 'wait() returned so the child with pid=-1 is finished'
Shell(pid = 6955) 2>
这是我正在做的作业,但我有点难过。
嗨,我正在尝试编写一个 shell 程序,但我不明白为什么 getline 会获取前面的输入行。
此外,该程序将执行“ls -al”、“pwd”和其他一些命令。但不仅仅是 ls.
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int tokenizer(char *str,char **argv);
void doCommand(char **argv);
int main()
{
pid_t pid;
char *command;
int Num_bytes_read;
size_t nbytes = 60;
int NumCommand = 0;
char **argv;
int NumOfArgs;
command = (char *) malloc (nbytes + 1);
command = NULL;
while(1)
{
NumCommand++;
printf("Shell(pid = %d) %d> ",getpid(),NumCommand);
fflush(stdin);
Num_bytes_read = getline(&command,&nbytes,stdin);
printf("command: %s",command);
if(Num_bytes_read == -1)
{
printf("\n ERRor\n");
}
else
{
int x = tokenizer(command,argv);
int i;
for (i = 0; i < (x+1); ++i)
printf ("argv[i] = %s\n",argv[i]);
//if (strcmp(argv[0], "quit")){
//break;
//}
doCommand(argv);
}
}
return 0;
}
int tokenizer(char *str, char **argv)
{
//const char s[2] = " ";
char ** res = NULL;
char * p = strtok (str, " \n");
int n_spaces = 0, i;
while (p)
{
res = realloc (res, sizeof (char*) * ++n_spaces);
if (res == NULL)
exit (-1); /* memory allocation failed */
res[n_spaces-1] = p;
argv[n_spaces-1]= res[n_spaces-1];
p = strtok (NULL, " \n");
}
// realloc one extra element for the last NULL
res = realloc (res, sizeof (char*) * (n_spaces+1));
res[n_spaces] = 0;
argv = res;
return n_spaces;
}
void doCommand(char **argv)
{
pid_t pid;
pid_t cpid; /* Pid of child to be returned by wait. */
int fd[2]; // dual pipeline
int status; /* Exit status of child. */
int nbytes;
int commandStatus;
pipe(fd);
pid = fork(); // Preceding with fork]
if (pid < 0)
{
printf("forking child process failed\n");
exit(1);
}
else if (pid == 0) // fork for the child
{
close(fd[0]); // close up reader side of pipe
cpid = getpid();
/* Send "string" through the output side of pipe */
write(fd[1], &cpid,sizeof(cpid));
//argv[0] = "ls";
//argv[1] = NULL;
commandStatus = execvp(*argv, argv);
if (commandStatus < 0) /* execute the command */
{
printf("Try again, command failed\n");
exit(1);
}
}
else if (pid > 1) // fork for the parent
{
close(fd[1]);
/* Read in the child pid from the pipe */
nbytes = read(fd[0], &cpid , sizeof(cpid));
printf("Parent says 'child process has been forked with pid=%ld'\n",(long)cpid);
wait(NULL);
cpid = wait(&status); /* wait for completion */
printf("Parent says 'wait() returned so the child with pid=%ld is finished'\n",(long)cpid);
}
}
问题是 argv
没有真正初始化,因为你改变的是 tokenizer()
中的局部指针,而不是 main()
中的指针。
你要做的就是传递argv
的地址而不是指针本身,然后像这样改变tokenizer()
int tokenizer(char *str, char ***argv)
{
char ** res = NULL;
char * p = NULL;
int n_spaces = 0;
if ((str == NULL) || (argv == NULL))
return 0;
p = strtok (str, " \n");
*argv = NULL;
while (p)
{
res = realloc (*argv, sizeof(char *) * ++n_spaces);
if (res == NULL)
{
free(*argv);
return 0;
}
res[n_spaces - 1] = p;
*argv = res;
p = strtok (NULL, " \n");
}
res = realloc (*argv, sizeof(char *) * (n_spaces + 1));
if (res == NULL)
{
free(*argv);
return 0;
}
res[n_spaces] = 0;
*argv = res;
return n_spaces;
}
在主要部分
int x = tokenizer(command, &argv);
/* ^ address of argv */
你也从来没有检查过最后一个 realloc
,所以我修复了一些我认为你做的有点不安全的事情。
exit()
on malloc
/realloc
失败在你的情况下并不是真正必要的,你可以只 free()
已经分配的指针和 return 0
,然后在 main()
.
中处理
此外,我建议在有意义的地方使用 const
限定词,例如
void doCommand(const char *const *argv)
另外,不要 fflush()
stdin
这是未定义的行为。
bdoetsch@Kaladin:~/Documents/School$ ./shell
Shell(pid = 6955) 1> ls
command: ls
argv[i] = ls
argv[i] = ./shell
Parent says 'child process has been forked with pid=6956'
./shell
Parent says 'wait() returned so the child with pid=-1 is finished'
Shell(pid = 6955) 2>
这是我正在做的作业,但我有点难过。
嗨,我正在尝试编写一个 shell 程序,但我不明白为什么 getline 会获取前面的输入行。
此外,该程序将执行“ls -al”、“pwd”和其他一些命令。但不仅仅是 ls.
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int tokenizer(char *str,char **argv);
void doCommand(char **argv);
int main()
{
pid_t pid;
char *command;
int Num_bytes_read;
size_t nbytes = 60;
int NumCommand = 0;
char **argv;
int NumOfArgs;
command = (char *) malloc (nbytes + 1);
command = NULL;
while(1)
{
NumCommand++;
printf("Shell(pid = %d) %d> ",getpid(),NumCommand);
fflush(stdin);
Num_bytes_read = getline(&command,&nbytes,stdin);
printf("command: %s",command);
if(Num_bytes_read == -1)
{
printf("\n ERRor\n");
}
else
{
int x = tokenizer(command,argv);
int i;
for (i = 0; i < (x+1); ++i)
printf ("argv[i] = %s\n",argv[i]);
//if (strcmp(argv[0], "quit")){
//break;
//}
doCommand(argv);
}
}
return 0;
}
int tokenizer(char *str, char **argv)
{
//const char s[2] = " ";
char ** res = NULL;
char * p = strtok (str, " \n");
int n_spaces = 0, i;
while (p)
{
res = realloc (res, sizeof (char*) * ++n_spaces);
if (res == NULL)
exit (-1); /* memory allocation failed */
res[n_spaces-1] = p;
argv[n_spaces-1]= res[n_spaces-1];
p = strtok (NULL, " \n");
}
// realloc one extra element for the last NULL
res = realloc (res, sizeof (char*) * (n_spaces+1));
res[n_spaces] = 0;
argv = res;
return n_spaces;
}
void doCommand(char **argv)
{
pid_t pid;
pid_t cpid; /* Pid of child to be returned by wait. */
int fd[2]; // dual pipeline
int status; /* Exit status of child. */
int nbytes;
int commandStatus;
pipe(fd);
pid = fork(); // Preceding with fork]
if (pid < 0)
{
printf("forking child process failed\n");
exit(1);
}
else if (pid == 0) // fork for the child
{
close(fd[0]); // close up reader side of pipe
cpid = getpid();
/* Send "string" through the output side of pipe */
write(fd[1], &cpid,sizeof(cpid));
//argv[0] = "ls";
//argv[1] = NULL;
commandStatus = execvp(*argv, argv);
if (commandStatus < 0) /* execute the command */
{
printf("Try again, command failed\n");
exit(1);
}
}
else if (pid > 1) // fork for the parent
{
close(fd[1]);
/* Read in the child pid from the pipe */
nbytes = read(fd[0], &cpid , sizeof(cpid));
printf("Parent says 'child process has been forked with pid=%ld'\n",(long)cpid);
wait(NULL);
cpid = wait(&status); /* wait for completion */
printf("Parent says 'wait() returned so the child with pid=%ld is finished'\n",(long)cpid);
}
}
问题是 argv
没有真正初始化,因为你改变的是 tokenizer()
中的局部指针,而不是 main()
中的指针。
你要做的就是传递argv
的地址而不是指针本身,然后像这样改变tokenizer()
int tokenizer(char *str, char ***argv)
{
char ** res = NULL;
char * p = NULL;
int n_spaces = 0;
if ((str == NULL) || (argv == NULL))
return 0;
p = strtok (str, " \n");
*argv = NULL;
while (p)
{
res = realloc (*argv, sizeof(char *) * ++n_spaces);
if (res == NULL)
{
free(*argv);
return 0;
}
res[n_spaces - 1] = p;
*argv = res;
p = strtok (NULL, " \n");
}
res = realloc (*argv, sizeof(char *) * (n_spaces + 1));
if (res == NULL)
{
free(*argv);
return 0;
}
res[n_spaces] = 0;
*argv = res;
return n_spaces;
}
在主要部分
int x = tokenizer(command, &argv);
/* ^ address of argv */
你也从来没有检查过最后一个 realloc
,所以我修复了一些我认为你做的有点不安全的事情。
exit()
on malloc
/realloc
失败在你的情况下并不是真正必要的,你可以只 free()
已经分配的指针和 return 0
,然后在 main()
.
此外,我建议在有意义的地方使用 const
限定词,例如
void doCommand(const char *const *argv)
另外,不要 fflush()
stdin
这是未定义的行为。