我有一个带参数的虚拟shell程序。但是,我希望它不带参数,而是提示让用户输入可执行程序和参数的名称。
例如:
$dummyshell
>(executable program and parameters go here)
这是我到目前为止的代码:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#define BUFFER_SIZE 1<<16
#define ARRAY_SIZE 1<<16
void parseCmdArgs(char *buffer, char** cmdArgs,
size_t cmdArgsSize, size_t *nargs)
{
char *bufCmdArgs[cmdArgsSize];
char **temp;
char *buf;
size_t n, p;
cmdArgs[0], buf, bufCmdArgs[0] = buffer;
for(temp=bufCmdArgs; (*temp=strsep(&buf, " \n\t")) != NULL ;){
if ((*temp != '\0') && (++temp >= &bufCmdArgs[cmdArgsSize]))
break;
}
for (p=n=0; bufCmdArgs[n]!=NULL; n++){
if(strlen(bufCmdArgs[n])>0)
cmdArgs[p++]=bufCmdArgs[n];
}
*nargs=p;
cmdArgs[p]=NULL;
}
int main(int argc, char *argv[], char *envp[]){
char buffer[BUFFER_SIZE];
char *args[ARRAY_SIZE];
char hflag = 'N';
int *retStatus;
size_t nargs;
pid_t pid;
while(1){
printf("$dummyshell ");
fgets(buffer, BUFFER_SIZE, stdin);
parseCmdArgs(buffer, args, ARRAY_SIZE, &nargs);
if (nargs==0)
continue;
if (!strcmp(args[0], "help"))
{
printf("cat cd (absolute path references only\n");
printf("exit\n");
printf("help history\n");
printf("jobs kill\n");
printf("ls more\n");
printf("ps pwd\n");
continue;
}
if (!strcmp(args[0], "exit" ))
exit(0);
pid = fork();
if (pid){
pid = wait(retStatus);
}
else {
if( execvp(args[0], args)) {
puts(strerror(errno));
exit(127);
}
}
}
return 0;
}
答案 0 :(得分:0)
您认为这条线有什么作用?
cmdArgs[0], buf, bufCmdArgs[0] = buffer;
它实际上评估了未初始化的cmdArgs[0]
并将其抛弃;然后它评估未初始化的buf
并将其抛出,最后分配给bufCmdArgs[0]
。如果要分配所有三个变量,请使用赋值运算符代替逗号运算符:
cmdArgs[0] = buf = bufCmdArgs[0] = buffer;
hflag
和main()
的参数均未使用;摆脱他们(int main(void)
)。你应该#include <sys/wait.h>
;您应该将retStatus
更改为简单的int
,然后将&retStatus
传递给wait()
。如果不这样做,您需要初始化retStatus
,使其指向可以分配到的int
。
通过这些更改,代码运行正常 - 有点像。它正确执行了ls -l
。但是,退出失败的 control-D (EOF)失败了(在我能够打断它之前,我已经看到了我的目录的简单ls
列表。
另外,你也会最终意识到命令cd和exit(也可能是历史)需要特别注意;它们是shell内置的有充分理由。然而,这是后来的。
您知道如何修改我的程序,以便用户输入'&amp;'程序结束时的符号及其参数,虚拟shell将在后台而不是前台运行程序?
是的,我知道如何做到这一点。基本上,您不执行wait()
(当您执行wait()
时,检查您收集信息的死进程是否是您期望的,或者它是否是您的shell的后台进程之一
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#define BUFFER_SIZE 1<<16
#define ARRAY_SIZE 1<<16
static void parseCmdArgs(char *buffer, char** cmdArgs,
size_t cmdArgsSize, size_t *nargs)
{
char *bufCmdArgs[cmdArgsSize];
char **temp;
char *buf;
size_t n, p;
cmdArgs[0] = buf = bufCmdArgs[0] = buffer;
for(temp=bufCmdArgs; (*temp=strsep(&buf, " \n\t")) != NULL ;){
if ((*temp != '\0') && (++temp >= &bufCmdArgs[cmdArgsSize]))
break;
}
for (p=n=0; bufCmdArgs[n]!=NULL; n++){
if(strlen(bufCmdArgs[n])>0)
cmdArgs[p++]=bufCmdArgs[n];
}
*nargs=p;
cmdArgs[p]=NULL;
}
//int main(int argc, char *argv[], char *envp[]){
int main(void)
{
char buffer[BUFFER_SIZE];
char *args[ARRAY_SIZE];
int retStatus;
size_t nargs;
pid_t pid;
while(1){
printf("$dummyshell ");
fgets(buffer, BUFFER_SIZE, stdin);
parseCmdArgs(buffer, args, ARRAY_SIZE, &nargs);
if (nargs==0)
continue;
if (!strcmp(args[0], "help"))
{
printf("cat cd (absolute path references only\n");
printf("exit\n");
printf("help history\n");
printf("jobs kill\n");
printf("ls more\n");
printf("ps pwd\n");
continue;
}
if (!strcmp(args[0], "exit" ))
exit(0);
pid = fork();
if (pid){
pid = wait(&retStatus);
}
else {
if( execvp(args[0], args)) {
puts(strerror(errno));
exit(127);
}
}
}
return 0;
}
您可能会注意到错误消息应该在标准错误上报告,而不是标准输出(因此puts(strerror(errno))
应该是fprintf(stderr, "%s\n", strerror(errno));
,因为fputs()
不会添加新行但puts()
确实)。