【问题标题】:Programming a shell in C用 C 编写一个 shell
【发布时间】:2012-09-24 03:45:46
【问题描述】:

我目前正在用 C 编写一个 shell,但遇到了一些问题。例如,当我尝试将我的命令与“退出”进行比较时,它只是在它上面运行 write 并且根据 gdb 表现得它们不相等。我以段错误结束。如果有人可以帮助我找出问题所在,我将不胜感激。顺便说一句,这是我的第一个 shell!

#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <limits.h>
#include <unistd.h>
#include <stdlib.h>
#include <pwd.h>
#include <dirent.h>e
#include <sys/types.h>
#include <sys/wait.h>    
#include <signal.h>
#include "sh.h"

int sh( int argc, char **argv, char **envp ){

    char *prompt = calloc(PROMPTMAX, sizeof(char));
    char *commandline = calloc(MAX_CANON, sizeof(char));
    char *command, *arg, *commandpath, *p, *pwd, *owd;
    char **args = calloc(MAXARGS, sizeof(char*));
    int uid, i, status, argsct, go = 1;
    struct passwd *password_entry;
    char *homedir;
    struct pathelement *pathlist;

    uid = getuid();
    password_entry = getpwuid(uid);
    homedir = password_entry->pw_dir; 

    if ( (pwd = getcwd(NULL, PATH_MAX+1)) == NULL ){
    perror("getcwd");
    exit(2);
    }

    owd = calloc(strlen(pwd) + 1, sizeof(char));
    memcpy(owd, pwd, strlen(pwd));
    prompt[0] = ' '; prompt[1] = '\0';

    pathlist = get_path();

    prompt = "[cwd]>";

    while ( go ){
    printf(prompt);

    commandline = fgets(commandline, 100, stdin);
    command = strtok(commandline, " ");

    printf(command);

    if (strcmp(command, "exit")==0){
        exit(0);
    }

    else if (strcmp(command, "which")==0){
    //  which();
    }

    else if (strcmp(command, "where")==0){
    //  where();
    }

    else if (strcmp(command, "cd")==0){
        chdir(argv[0]);
    }

    else if (strcmp(command, "pwd")==0){
        getcwd(pwd, PATH_MAX);
    }

    else if (strcmp(command, "list")==0){
        if (argc == 1){

        }

        else if (argc > 1){

        }
    }

    else if (strcmp(command, "pid")==0){
        getpid();
    }

    else if (strcmp(command, "kill")==0){

    }

    else if (strcmp(command, "prompt")==0){
        prompt = "argv[0] + prompt";
    }

    else if (strcmp(command, "printenv")==0){

    }

    else if (strcmp(command, "alias")==0){

    }

    else if (strcmp(command, "history")==0){

    }   

    else if (strcmp(command, "setenv")==0){

    }

    else{
        fprintf(stderr, "%s: Command not found.\n", args[0]);
    }



}
return 0;

} 

其中大部分仍然是裸露的骨头,所以请耐心等待。

【问题讨论】:

  • 您可能想尝试代码审查堆栈交换。 codereview.stackexchange.com
  • @OmnipotentEntity: 否 -- CodeReview 适用于有效的代码。
  • 我首先创建一个“映射”,从命令名称到执行这些功能的函数,而不是巨大的 if/then/else 阶梯。
  • 去过那里。我可以提个建议吗?使用调度表而不是所有那些else ifs,坦率地说这是不可扩展的。创建一个 char 数组的结构来保存内置名称,以及一个指向内置函数的函数指针(所有函数都应该具有相同的原型)。创建这些结构的数组,按内置名称手动排序并使用bsearch 为每个内置找到正确的函数。

标签: c shell unix


【解决方案1】:

如果你改变:

printf(command);

进入:

printf("<<%s>>\n",command);

你会明白为什么它永远不会匹配这些字符串中的任何。那是因为fgets 没有去掉尾随的换行符 (a):

[cwd]>ls
<<ls
>>

这意味着它将执行这行代码:

fprintf(stderr, "%s: Command not found.\n", args[0]);

而且,既然您已经使用您的 calloc 将所有这些 args[] 值初始化为 NULL,BANG!去你的代码(试图取消引用空指针是未定义的行为)。

去看看this answer 以获得一个强大的用户输入解决方案,它具有提示、缓冲区溢出保护、忽略剩余的过长行以及最重要的是去掉换行符。


(a) 顺便说一句,您不应该将用户输入作为格式字符串传递给printf。猜猜如果我在提示符下输入%s%s%s%s%s%s 会发生什么:-)

而且,与您的问题无关,ISO C 要求 sizeof(char)始终为 1,因此您不需要 在分配语句中使用它 - 我发现它只是不必要地阻塞了代码。

【讨论】:

  • 我认为这是我 strtok 部分命令的重点,尽管它是为了摆脱所有的“空白”。也许我只是错过了 strtok 的重点?我不确定。
  • @Requiem: 是的,除了你的 strtok 没有 摆脱空白。它根据空格标记字符串。 如果你的输入字符串是“ls\n”,你的strtok 不会去掉换行符。它适用于其中包含空格的多字命令(嗯,直到最后一个,它仍然会有换行符),但不适用于根本没有空格的东西。如果要在空格 换行符上加上 strtok,则需要在分隔符字符串中同时提供它们。
  • 因此,如果我想标记命令但又想摆脱新行问题,我只需要做 strtok(c​​ommandline, " \n"); ?
  • 它似乎奏效了我只是想知道它是否还能让我标记化?
  • @Requium,我自己会在 fgets 之后直接去掉换行符,但是用两个字符进行标记也应该可以工作。
猜你喜欢
  • 2015-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-29
  • 1970-01-01
  • 2011-02-05
  • 2020-07-22
  • 1970-01-01
相关资源
最近更新 更多