【问题标题】:Forking with command line arguments使用命令行参数进行分叉
【发布时间】:2013-04-13 11:16:05
【问题描述】:

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

目前,所有输入都在全局变量 char * parsed_arguments 中以空格和换行符进行标记。例如,输入 dir /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);

      }

    }

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

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

【问题讨论】:

  • 每个命令的参数列表末尾是否有一个空指针?
  • @JonathanLeffler 它们都应该是字符串,最后应该有一个空指针。
  • 好的;这是避免的一个陷阱。在分叉代码中,这是一个错字吗? execv(parsed_arguments[0], passed_arguments); 应该在哪里 execv(parsed_arguments[0], parsed_arguments);?请注意,如果execv() 返回,它会失败,但您的代码会继续让失败的孩子继续。在失败的execv() 或等效项之后几乎总是exit() 或等效项。也推荐留言。
  • 仔细阅读简介,我发现您同时拥有parsed_argumentspassed_arguments;这些名称彼此非常接近,容易引起混淆和错误。不要忘记传递给向量中execv() 的参数包括位置 0 处的程序名称。如果您的 passed_arguments 数组省略了命令名称,您将丢失命令的第一个参数(它被视为命令名称)。
  • 将一些 cmets 处理成一个答案...请研究产生 SSCCE 的含义 (Short, Self-Contained, Correct Example)。一条评论:这段代码全局变量太多,函数参数不够。

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


【解决方案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() 也是合理的,只是它不必要地依赖于全局变量。将全局变量视为难闻的气味(例如 H2S);尽可能避免它们。它应该更像:

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

如果您无法使用 C89,则需要在循环外部声明 int i; 并在循环控件中仅使用 for (i = 1; ...)。请注意,此处的打印将每个参数单独分隔在一行中,并将其括在标记字符中(&lt;&lt;&gt;&gt; — 更改以适应您的突发奇想和偏见)。可以跳过循环中的换行符(可能使用空格代替),然后在循环后添加换行符(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 代码对其进行编辑,并通过对此答案的评论通知我,以便我看到您已完成此操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-16
    • 2014-05-23
    • 2013-10-30
    • 1970-01-01
    • 1970-01-01
    • 2010-09-22
    • 1970-01-01
    相关资源
    最近更新 更多