构建简单的unix shell问题

时间:2016-01-20 21:59:30

标签: shell unix fork tokenize execvp

我是unix的新手,我在大学里有一个使用内置cd和kill命令在c中构建一个简单shell的assignemnt。 这是我的代码,它不起作用..我不理解它是最好的所以我并不惊讶它不工作..你能帮助我吗?也不知道我将如何实现kill命令。谢谢!

#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define BUF_SIZE 1024



const int ARGSIZE = 20;

void execute(char*args[])
{

    int pid, status;
    pid = fork();

    if(pid<0)
    {
        perror("Error forking!");
    }

    else if(pid > 0)
    {
        while(wait(&status) != pid)
            continue;
    }

    else if(pid == 0)
    {
    if (execvp(args[0], args) == -1)
    {
        perror("Error");
    }
    }
}

void cd(char*directory)
{
    int ret = 0;

   if(directory == '\0')
      directory = getenv("HOME");

    ret = chdir(directory);

    if(ret != 0)
        fprintf(stderr,"Failed to enter directory: %s\n",directory);
    else
        printf("%s\n",directory);

}


int main()
{
    char line[BUF_SIZE];
    char *args[ARGSIZE];
    int argIndex = 0;


    while(1){
    printf("> ");

    fgets(line, BUF_SIZE, stdin);
    char *token;
    token = strtok(line," "); 

    while(token!=NULL)
    {
        args[argIndex]=token;
        token = strtok(NULL," ");
        argIndex++;
    }
    args[argIndex]=NULL; 


    if(strcmp(args[0], "quit") == 0 || strcmp(args[0], "exit") == 0)
        break;

    if(line== "\n")
        printf("> "); 
    else if ((strcmp(args[0], "cd") == 0))
        cd(args[1]); 
    else
        execute(args); 

    }
  return 0;
}

1 个答案:

答案 0 :(得分:0)

你走在正确的轨道上。有一些微妙的问题,您没有考虑将'\n'作为跟随输入后的最后一个字符的line的尾随" \n"。在用于使用strtok标记输入的分隔符中包含strcmp将删除它,允许与最终标记进行有效quit比较(例如,这就是为什么exit和{{1不会退出应用程序)。

除了之外,还有一些额外的东西你可以做一些不同/更好的事情,你可以处理输入的目录,例如'~/somedir',以及可以采用的类似附加检查。我在下面注明了对代码的评论。

查看下面的更改,如果您有任何疑问,请与我们联系。总有额外的检查可以添加,等等。但总的来说,你解决问题的方法非常好。 (注意:所做的一些更改是非实质性的,例如"shell> "作为提示,而不是"> "。只需按照您的意愿处理任何更改。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

enum {ARGSIZE = 20, BUF_SIZE = 1024};

void execute (char **args);
void cd (char *directory);
int killpid (char *pitstr, int sig);

int main (void)
{
    char line[BUF_SIZE] = {0};
    char *args[ARGSIZE] = {NULL};
    char *token;
    int i, argIndex = 0;

    while (1) {

        argIndex = 0;   /* reinitialize variables */
        for (i = 0; i < ARGSIZE; i++)
            args[i] = NULL;

        printf ("shell> "); /* prompt */

        if (fgets (line, BUF_SIZE, stdin) == NULL) {
            printf ("EOF received\n");
            return 0;
        }
        if (*line == '\n')  /* Enter alone */
            continue;

        token = strtok (line, " \n"); /* add \n to delimiters */

        while (token != NULL) {
            args[argIndex] = token;
            token = strtok (NULL, " \n");
            argIndex++;
        }
        if (!argIndex) continue;    /* validate at least 1 arg */

        if (strcmp (args[0], "quit") == 0 || strcmp (args[0], "exit") == 0)
            break;

        /* handle 'cd' or 'kill' separately */
        if ((strcmp (args[0], "cd") == 0))
            cd (args[1]);
        else if ((strcmp (args[0], "kill") == 0)) {
            if (args[1]) killpid (args[1], SIGTERM);
        }
        else
            execute (args);

    }
    return 0;
}

void execute (char **args)
{
    int pid, status;
    pid = fork ();

    if (pid < 0) {
        perror ("Error forking!");
        return;
    }
    else if (pid > 0) {
        while (wait (&status) != pid)
            continue;
    }
    else if (pid == 0) {
        if (execvp (args[0], args) == -1) {
            perror ("Error");
        }
        _exit (EXIT_FAILURE);
    }
}

void cd (char *directory)
{
    char dir[BUF_SIZE] = {0};

    if (!directory) {   /* handle 'cd' */
        directory = getenv ("HOME");
        if (chdir (directory))
            fprintf (stderr, "Failed to enter directory: %s\n", directory);
        else
            printf ("%s\n", directory);
        return;
    }

    if (*directory == '~') { /* handle cd ~/stuff */
        strcpy (dir, getenv ("HOME"));
        strcat (dir, "/");
        strcat (dir, directory + 2);
        if (chdir (dir))
            fprintf (stderr, "Failed to enter directory: %s\n", dir);
        else
            printf ("%s\n", dir);
        return;
    }

    if (chdir (directory))  /* handle given directory */
        fprintf (stderr, "Failed to enter directory: %s\n", directory);
    else
        printf ("%s\n", directory);
}

int killpid (char *pidstr, int sig)
{
    pid_t pid = (pid_t)atoi (pidstr);
    if (pid < 1) {
        fprintf (stderr, "warning: requested pid < 1, ignoring\n");
        return (int)pid;
    }

    printf (" killing pid '%d' with signal '%d'\n", (int)pid, sig);
    // return kill (pid, sig);
    return 0;
}

样本使用/输出

$ ./bin/ushell
shell> cd
/home/david
shell> cd ~/tmp
/home/david/tmp
shell> kill 18004
 killing pid '18004' with signal '15'
shell>
shell> quit