1

我正在构建一个 Linux Shell,我目前的头痛是将命令行参数传递给分叉/执行的程序和系统函数。

目前,所有输入都在全局变量 char * parsed_arguments 中以空格和换行符标记。例如,输入目录 /usa/folderb将被标记为:

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

parsed_arguments 完美地标记了一切;我现在的问题是我希望只获取 parsed_arguments 的一个子集,它不包括要在 shell 中运行的可执行文件的命令/第一个参数/路径,并将它们存储在一个名为 pass_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);

      }

    }

在此处输入图像描述

这是我的外壳当前输出的内容。我第一次运行它时,它会输出一些接近我想要的东西,但每次后续调用都会破坏程序。此外,每个额外的调用都会将解析的参数附加到输出中。

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

4

1 回答 1

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 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 代码对其进行编辑,并通过对此答案的评论通知我,以便我看到您已完成此操作。

于 2013-04-20T02:09:49.910 回答