使用命令行参数进行分叉

时间:2013-04-20 00:11:52

标签: c linux exec fork command-line-arguments

我正在构建一个Linux Shell,我目前头痛的是将命令行参数传递给forked / 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目前输出的内容。我第一次运行它时会输出接近我想要的东西,但是每次后续调用都会破坏程序。此外,每个附加调用都会将解析后的参数附加到输出中。

这是原始shell产生的。它再次接近我想要的,但并不完全。我想省略命令(即“./testline”)。

1 个答案:

答案 0 :(得分:1)

您的testline程序在您的工具箱中是明智的;我有一个类似的程序,我称之为al(对于Argument List)打印其参数,每行一个。它不会打印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 2 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代码对其进行编辑,并通过对此答案的评论通知我,以便我看到您已完成此操作。