【问题标题】:Simple Shell in C [closed]C中的简单外壳[关闭]
【发布时间】:2013-12-16 19:00:33
【问题描述】:

我正在从事一个学校项目,该项目基本上是在 UNIX 中创建一个简单的 shell。 但我被我项目的历史部分困住了。关于历史部分的解释如下:

history - 此命令用于维护以前发出的命令的历史记录。

o 历史记录 - 在您的 shell 中打印最多 10 个最近输入的命令。

哦! number - 用户应该能够通过以下方式重复先前发出的命令 打字! number,其中 number 指示要重复哪个命令。

请注意! 1 用于重复返回的命令列表中编号为 1 的命令 历史,和! -1 用于重复上一个命令。

我的代码直到历史部分在这里:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <limits.h>
#include <malloc.h>
#include <string.h>
#include <termios.h>
#include <errno.h>

#define CREATE_FLAGS (O_WRONLY | O_CREAT | O_APPEND)
#define CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
#define CREATE_FLAG (O_WRONLY| O_CREAT| O_TRUNC)
#define MAXCHARNUM 128 
#define MAXARGNUM 32 
char *argsexec[MAXARGNUM];
char str[MAXCHARNUM];
char *path;
char *name;

struct Node
{

  pid_t pid;
  char *pname;
  int index;
  struct Node *nextPtr;
};
typedef struct Node Node;
typedef struct Node *NodePtr;

NodePtr list = NULL;

void addJob(NodePtr *currentPtr, pid_t pid, char *name, int indx)
{

  NodePtr newPtr, prePtr, curPtr;
  newPtr = malloc(sizeof(Node));

  if (newPtr != NULL )
  {

    newPtr->pid = pid;
    newPtr->pname = name;
    newPtr->index = indx;
    newPtr->nextPtr = NULL;
    prePtr = NULL;
    curPtr = *currentPtr;

    while (curPtr != NULL )
    {
      prePtr = curPtr;
      curPtr = curPtr->nextPtr;
    }

    if (prePtr == NULL )
    {
      newPtr->nextPtr = *currentPtr;
      *currentPtr = newPtr;
    }
    else
    {
      prePtr->nextPtr = newPtr;
      newPtr->nextPtr = curPtr;
    }
  }
}

void printJob(NodePtr curPtr)
{
  if (curPtr == NULL )
  {
    printf("Running: List is empty.\n");
    printf("Terminated: List is empty.\n");
  }
  else
  {
    printf("Running:\n");

    while (curPtr != NULL )
    {
      printf("[%d] --> %s\n", curPtr->index, curPtr->pname);
      curPtr = curPtr->nextPtr;
    }
    printf("Finished:\n");

    while (curPtr != NULL )
    {
      printf("[%d] --> %s (pid = %d)\n", curPtr->index, curPtr->pname,
          curPtr->pid);
      curPtr = curPtr->nextPtr;
    }
  }
}

void ioredirection()
{

  int input = -1, output = -1, append = -1;
  int k, d, fdinput, fdoutput;
  for (k = 0; argsexec[k] != NULL ; k++)
  {

    if (strcmp(argsexec[k], "<") == 0)
    {
      argsexec[k] = NULL;
      input = k;
      d = 1;
    }
    else if (strcmp(argsexec[k], ">") == 0)
    {
      argsexec[k] = NULL;
      output = k;
      d = 2;
    }
    else if (strcmp(argsexec[k], ">>") == 0)
    {
      argsexec[k] = NULL;
      append = k;
      d = 3;
    }
    if (d == 1)
    {
      fdinput = open(argsexec[input + 1], O_RDONLY, 0);
      dup2(fdinput, STDIN_FILENO);
      close(fdinput);
      execvp(argsexec[0], argsexec);
    }
    if (d == 2)
    {
      int x, y;
      char buffer[1024];

      fdinput = open(argsexec[output - 1], O_RDONLY);
      fdoutput = open(argsexec[output + 1], CREATE_FLAG, CREATE_MODE);

      dup2(fdoutput, STDOUT_FILENO);
      x = read(fdinput, buffer, 1024);
      write(fdoutput, buffer, x);

      close(fdinput);
      close(fdoutput);

      for (y = output; y < MAXARGNUM - 2; y++)
        argsexec[y] = argsexec[y + 2];
      argsexec[MAXARGNUM - 2] = NULL;
    }
    if (d == 3)
    {
      int x, y;
      char buffer[1024];

      fdinput = open(argsexec[output - 1], O_RDONLY);
      fdoutput = open(argsexec[output + 1], CREATE_FLAGS, CREATE_MODE);

      x = read(fdinput, buffer, 1024);
      write(fdoutput, buffer, x);

      close(fdinput);
      close(fdoutput);
    }
  }

}
void add_path(char **dir, const char *begin, const char *end) //do the memory allocations, and add to the specified arrays.
{
  if (end == begin)
  {
    begin = " ";
    end = begin + 1;
  }
  size_t len = end - begin;
  *dir = malloc(len + 1);
  memmove(*dir, begin, len);
  (*dir)[len] = '\0';

}

size_t tokenize(const char *path, char **dirs, size_t max_dirs, char delim) //tokenize the given input, with the given delimiter
{                        //returns the size of the splitted parts of the string.
  const char *begin = path;
  const char *end;
  size_t num_dirs = 0;

  while (num_dirs < max_dirs && (end = strchr(begin, delim)) != 0)
  {
    add_path(&dirs[num_dirs++], begin, end);
    begin = end + 1;
  }
  if (num_dirs < max_dirs && *begin != '\0')
    add_path(&dirs[num_dirs++], begin, begin + strlen(begin));
  return num_dirs;
}

void clearArgs()
{

  int i;
  for (i = 0; i < MAXARGNUM; ++i)
  {
    argsexec[i] = NULL;
  }
}

int Ampersand()
{
  int i;
  for (i = 0; argsexec[i] != NULL ; i++)
  {
    if (strcmp(argsexec[i], "&") == 0)
    {
      return 1;
    }
    else
    {
      return 0;
    }
  }
}

void Setup()
{

  while (1)
  {
    path = malloc((MAXCHARNUM + 1) * sizeof(char));
    clearArgs();

    fprintf(stderr, "333sh: ", NULL );
    gets(str);  //get the next commands

    while (strlen(str) == 0)
    { //if the user enters empty string or space, ignore this input, read again.
      fprintf(stderr, "333sh: ", NULL );
      gets(str);
    }

    size_t commands = tokenize(str, argsexec, MAXARGNUM, ' ');
    const char *path = getenv("PATH");  //get the system's path   
    ioredirection();
    char * const arguments[] =
    { argsexec[0], argsexec[1], argsexec[2], argsexec[3], argsexec[4],
        argsexec[5], argsexec[6], argsexec[7], (void*) NULL };

    name = argsexec[0];
    pid_t pid = fork();
    wait(NULL );

    if (Ampersand())
    {
      if (pid == 0)
      {
        int in = 1;
        addJob(&list, pid, name, in);

      }
    }
    if (pid == 0)
    {
      if (!Ampersand())
      {

        if (path == NULL )
        {  //execl part
          execl(path, argsexec[0], argsexec[1], argsexec[2], argsexec[3],
              argsexec[4], argsexec[5], argsexec[6], argsexec[7], NULL );
        }
        else if (strcmp(argsexec[0], "dir") == 0 && argsexec[1] == NULL )
        {
          system("ls");
        }

        else if (strcmp(argsexec[0], "clr") == 0)
        {
          system("clear");
        }
        else if (strcmp(argsexec[0], "cd") == 0 && argsexec[1] == NULL )
        {
          system("pwd");
        }
        else if (strcmp(argsexec[0], "list_jobs") == 0 && argsexec[1] == NULL )
        {
          printJob(list);

        }
        else
        {  //execvp part

          execvp(argsexec[0], arguments);
        }

      }
    }
  }
}

int main(int argc, char const *argv[])
{
  Setup();
  return 0;

}

那么我该如何设计这个项目的历史部分呢?任何想法都将不胜感激。很抱歉问了这么长的代码。 谢谢

【问题讨论】:

    标签: c bash shell unix


    【解决方案1】:

    一种方法是最初创建一个包含 10 个指向 NULL 的指针的数组。添加一个例程update_history(&lt;cmd issued&gt;) 或这样您在您允许在您的shell 中的每个命令之后调用。它应该:

    (1) 第一次调用:malloc() 用于发出第一个命令的空间,并存储指向 数组第一个位置的堆区域
    (2) 稍后调用:使用 NULL 指针检查数组的第一个位置,并在其中存储指向命令的指针(再次使用 malloc() )。如果在数组中没有找到 NULL 指针(历史是 10 个命令长),请转到 (3)
    (3) 执行另一个新的例程move_history(cmd issued)。它将第二个数组位置(指针)移动到第一个,第 3 个到第 2 个,...,第 10 个到第 9 个,并插入一个指向 &lt;cmd_issued&gt; 在堆上的存储位置的指针(使用另一个 malloc())进入最后一个数组位置。不要忘记free() 为以前不再跟踪的第一个元素分配的堆内存。

    然后您可以非常轻松地打印出整个历史记录(通过指针数组打印,直到找到一个 NULL 指针,但不超过 10 个 p/os;并打印命令历史编号 1-10(或 0-9 ) 在字符串之前);并打印特定命令,您知道指向它的指针在哪个数组行中(如果基于 1 的编号,则在行 i-1 中)。然后,您可以阅读它并重新发出命令(不要忘记也将这部分记录在您的历史记录中)。

    【讨论】: