我已经使用 c 程序实现了类似 shell 的简单 bash,但它没有按预期工作

Posted

技术标签:

【中文标题】我已经使用 c 程序实现了类似 shell 的简单 bash,但它没有按预期工作【英文标题】:I have implemented simple bash like shell using c program but its not working as expected 【发布时间】:2019-06-03 12:34:34 【问题描述】:

我已经创建了一个类似 bash 的程序,但是当我尝试执行它时,它在第一次运行良好,但在它没有按预期运行之后

最后执行的输出重复显示而不是询问新的输入

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

 char full_cmd[20];

 void command_source(char *cmd)
 

    FILE *fp;
    char output[20];
    char *token;
    token = strtok(cmd," ");
    strcpy(full_cmd,"which ");
    strcat(full_cmd,token);
    fp = popen(full_cmd,"r");
    while (fgets(output, 20, fp) != NULL) 
            strcpy(full_cmd,output);
    
    full_cmd[strlen(full_cmd)-1] = '\0';

    token = strtok(NULL," ");
    while (token != NULL)
    
            strcat(full_cmd,token);
            token = strtok(NULL," ");
    

  

  void get_input(char input[10])
   
    printf("Enter the command:");
    scanf("%[^\n]s",input);
  

  int launch_shell(char *buff[50],int status)
  
    pid_t pid = fork();
    if( pid == 0 )
    
            execv(buff[0],buff);
    
    else if (pid > 0)
    
            pid_t wpid = waitpid(pid, &status, 0);
    
    else
            return 0;
    return 1;
  

  int main()
  
    char *buff[50];
    int status;
    char input[10];
    int count=0,ret=1;
    while(ret == 1)
    
            get_input(input);
            command_source(input);
            strcpy(buff[0],full_cmd);
            buff[1] = NULL;
            int ret = launch_shell(buff,status);
    
  

预期:

Enter the command:ls 
server.c server
Enter the command:ls -l
server.c
server

实际结果:

Enter the command:ls
server  server.c
server  server.c
server  server.c
server  server.c
server  server.c
server  server.c
server  server.c
server  server.c
server  server.c
server  server.c
server  server.c
server  server.c
server  server.c
server  server.c
...

请帮助我找出问题所在。我花了一整天来解决这个问题。但我做不到。

【问题讨论】:

您忽略了 scanf() 的返回值,风险自负。考虑不要。 【参考方案1】:

附言

scanf("%[^\n]s",input);

您是在说“阅读直到有换行符”。因此,在第一次输入之后,换行符会留在输入流中,从而防止立即停止后续输入读取。更好的主意是使用fgets() 而不是scanf()

您可以将 size 参数传递给 get_input 函数,例如:

  void get_input(char input[10], size_t size)
   
    printf("Enter the command:");
    if (fgets(input, size, stdin) != NULL) 
        char *p = strchr(input, '\n');
        if (p) *p = '\0';
     else 
        fprintf(stderr, "fgets failed\n");
        exit(1);
    
  

然后调用它:

    get_input(input, sizeof input);

你还有很多问题:

1.

strcpy(buff[0],full_cmd);

不正确,因为 buff[0] 未初始化。您可以改为分配:

buff[0] = full_cmd;

    在您当前的方法中,您不能为命令提供参数。因为每个参数和命令都需要作为数组buffexecv的不同参数传递。

    所以你需要在调用launch_shell之前根据空格分割输入并放入数组buff。例如,“ls -l”将是execv 的单个参数(通过buff[0] 传递)。但这不是execv 接受的。您需要将“ls”放入buff[0],将“-l”放入buff[1],将NULL 放入buff[2],然后调用execv

【讨论】:

但即使是简单的“ls”,我也会遇到同样的问题 这是因为首先注意到的问题:有一个换行符 (\n) 会立即阻止 scanf 读取进一步的输入。 刚刚更新以展示如何使用fgets 进行输入读取。但如前所述,您仍然需要拆分 args 以便执行带参数的命令。

以上是关于我已经使用 c 程序实现了类似 shell 的简单 bash,但它没有按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

如何用 C 语言写一个简单的 Unix Shell

简单的无锁堆栈c ++ 11

shell脚本基础 -----简单脚本的实现

急救:编写一个简单的Shell程序,实现将指定的文件内容中小写字母转换成大写字母显示出来。

Shell之/bin/bash脚本的基础实战

Shell之/bin/bash脚本的基础实战