2013-04-20 59 views
1

我正在构建一个Linux Shell,而我目前头疼的是将命令行参数传递给fork/exec'ed程序和系统函数。用命令行参数分叉

当前所有输入都在空格和新行上标记为全局变量char * parsed_arguments。例如,输入DIR/USA/FolderB中将被标记化如:

parsed_arguments[0] = dir 
parsed_arguments[1] = /usa/folderb 

parsed_arguments一切标记化完美;我现在的问题是,我只希望获取一部分parsed_arguments,它排除了要在shell中运行的可执行文件的命令/第一个参数/路径,并将它们存储在一个名为passed_arguments的新数组中。

所以在前面的例子DIR/USA/FolderB中

parsed_arguments[0] = dir 
parsed_arguments[1] = /usa/folderb 

passed_arguments[0] = /usa/folderb 
passed_arguments[1] = etc.... 

目前,我不会有这个,所以我希望有人能够帮助我运气好的话。以下是我迄今为止的工作的一些代码:

我如何试图复制参数:

void command_Line() 
{ 

    int i = 1; 
    for(i;parsed_arguments[i]!=NULL;i++) 
    printf("%s",parsed_arguments[i]); 

} 

功能来读取命令:

void readCommand(char newcommand[]){ 

printf("readCommand: %s\n", newcommand); 


//parsed_arguments = (char* malloc(MAX_ARGS)); 
// strcpy(newcommand,inputstring); 
    parsed = parsed_arguments; 
    *parsed++ = strtok(newcommand,SEPARATORS); // tokenize input 
    while ((*parsed++ = strtok(NULL,SEPARATORS))) 
     //printf("test1\n"); // last entry will be NULL 

     //passed_arguments=parsed_arguments[1]; 

    if(parsed[0]){ 
     char *initial_command =parsed[0]; 

    parsed= parsed_arguments; 
    while (*parsed) fprintf(stdout,"%s\n ",*parsed++); 
    // free (parsed); 
    // free(parsed_arguments); 

    }//end of if 


    command_Line(); 

}//end of ReadCommand 

分叉功能:

else if(strstr(parsed_arguments[0],"./")!=NULL) 
    { 
     int pid; 
     switch(pid=fork()){ 
     case -1: 
     printf("Fork error, aborting\n"); 
     abort(); 
     case 0: 
     execv(parsed_arguments[0],passed_arguments); 

     } 

    } 

enter image description here

这是我的shell当前输出的内容。我第一次运行它时,它会输出接近我想要的东西,但随后的每次调用都会中断程序。另外,每个额外的调用都会将分析的参数附加到输出中。

这是原来的外壳生产什么。再次,它接近我想要的,但不完全。我想省略该命令(即“./testline”)。

+0

每个命令的参数列表末尾是否有空指针? – 2013-04-20 00:14:04

+0

@JonathanLeffler它们都应该是字符串,最后应该有一个空指针。 – blutuu 2013-04-20 00:15:01

+0

好的;这是一个陷阱避免。在分叉代码中,这是一个错字吗? 'execv(parsed_arguments [0],passed_arguments);'它应该是'execv(parsed_arguments [0],parsed_arguments);'?请注意,如果'execv()'返回,它将失败,但代码继续让失败的子继续。几乎总是'exit()'或等效的'execv()'失败后的等价物。并且也建议一条消息。 – 2013-04-20 00:18:18

回答

1

您的testline程序在您的工具箱中是明智的;我有一个类似的程序,我打电话给al(用于参数列表),打印它的参数,每行一个。它不打印argv[0]虽然(我知道它被称为al)。您可以轻松安排您的testline也跳过argv[0]。请注意,Unix约定是argv[0]是程序的名称;你不应该试图改变这种情况(你会对整个系统进行战斗)。

#include <stdio.h> 

int main(int argc, char **argv) 
{ 
    while (*++argv != 0) 
     puts(*argv); 
    return 0; 
} 

您的函数command_line()除了不必要地使用全局变量之外也是合理的。把全局变量想象成一种讨厌的气味(例如,H S);尽可能避免它们。它应该更像:

void command_Line(char *argv[]) 
{ 
    for (int i = 1; argv[i] != NULL; i++) 
     printf("<<%s>>\n", argv[i]); 
} 

如果你坚持C89,你需要声明int i;外循环,并在闭环控制只使用for (i = 1; ...)。请注意,此处的打印将每个参数自行分隔开,并将其包含在标记字符中(<<>> - 更改以适应您的偏见和偏见)。可以跳过循环中的换行符(也许使用空格),然后在循环后添加一个换行符(putchar('\n');)。这使得更好,更接近通用调试例程。 (当我编写“转储”功能时,我通常使用void dump_argv(FILE *fp, const char *tag, char *argv[])以便我可以打印到标准错误或标准输出,并包含标记字符串以标识转储的写入位置。)

不幸的是,鉴于零碎的性质你的readCommand()功能,它是不可能连贯地批评它。注释掉的行足以引起人们的关注,但是如果没有你正在运行的实际代码,我们无法猜测你正在做什么问题或错误。如图所示,它是等效于:

void readCommand(char newcommand[]) 
{ 
    printf("readCommand: %s\n", newcommand); 

    parsed = parsed_arguments; 
    *parsed++ = strtok(newcommand, SEPARATORS); 
    while ((*parsed++ = strtok(NULL, SEPARATORS)) != 0) 
    { 
     if (parsed[0]) 
     { 
      char *initial_command = parsed[0]; 
      parsed = parsed_arguments; 
      while (*parsed) 
       fprintf(stdout, "%s\n ", *parsed++); 
     } 
    } 

    command_Line(); 
} 

变量parsedparsed_arguments都是全局和可变initial_command被设置但不使用(又名“无意义”)。 if (parsed[0])测试不安全;你在前一行增加了指针,所以它指向了不确定的内存。

从表面上看,从屏幕截图判断,在第二次使用时,您没有正确重置parsed_arguments[]和/或passed_arguments[]阵列;它可能是一个没有被设置为零的索引。不知道如何分配数据,很难知道你可能会做错什么。

我建议关闭这个问题,回到你的系统并产生一个最小的SSCCE。它应该在大约100行以下;它不需要执行execv()(或fork()),但应该使用上述command_Line()函数的变体来打印要执行的命令。如果此答案阻止您删除(关闭)此问题,请使用您的SSCCE代码对其进行编辑,并通过评论回复此答案,以便我看到您已完成此操作。