【问题标题】:C - A simple shell on linux - Some trouble with commandsC - linux上的一个简单的shell - 命令的一些问题
【发布时间】:2013-12-06 11:49:45
【问题描述】:

到目前为止,我编写了这个简单的 shell。但是我的外壳遇到了一些麻烦。 例如,当我尝试通过命令“evince pdffile.pdf”打开一个 pdf 文件时,实际的 pdfile 并没有被打开。 pdf 查看器运行,但包含全部内容的实际文件永远不会出现。 或者另一个例子是命令“ls -l”。我没有得到应有的文件和文件夹,但“ls”正在工作。 另一个例子是gedit,等等。 另外,我应该提一下。我没有使用“system()”,因为 system() 会做所有事情,而我无事可做。相反,我使用的是“execvp()”。 这是代码。我希望你能找到问题所在,因为我不知道问题是什么原因造成的。

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

#define MAX_LENGTH 1024
#define DELIMS " \t\r\n"

void exec_cmd (char *buf);

int main() {    
   char line[MAX_LENGTH];
   char * cmd;
   char curDir[100];

   while (1) {  
       getcwd(curDir, 100);
       printf("%s@%s$ ", getlogin(), curDir);
       if (!fgets(line, MAX_LENGTH, stdin))
           break;

       if ((cmd = strtok(line, DELIMS))) {
           errno = 0;
           if (strcmp(cmd, "cd") == 0) {
              char *arg = strtok(0, DELIMS);

              if (!arg) 
                 fprintf(stderr, "cd: argument is missing.\n");
              else chdir(arg);

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

           } else exec_cmd(line);

        if (errno) perror("Error. Command failure");
        }
   }
return 0;
}

void exec_cmd (char *buf) {
    int status = 0;
    char *argv[MAX_LENGTH];
    int j=0;
    pid_t pid;
    argv[j++] = strtok (buf, DELIMS);
    while (j<MAX_LENGTH && (argv[j++]=strtok(NULL,DELIMS))!=NULL); // EDIT: " " replaced by DELIMS 

    pid = fork();
    if(pid < 0) {
       printf("Error occured");
       exit(-1);
    } else if(pid == 0) {
         execvp(argv[0],argv);
    } else if( pid > 0) {
         wait(&status);
    }
}   

【问题讨论】:

    标签: c linux bash shell command-line-arguments


    【解决方案1】:

    在调用fork/exec 之前检查参数(例如,打印出来,每个都包含在[] 中),很有可能它们不是你想的那样。

    虽然您对 strtok 的第一次调用使用了完整的分隔符集,但后续调用不会。相反,他们只使用一个空间。这意味着最后一个参数可能会在字符串上留下fgets 的换行符。我将在后续调用中使用相同的分隔符集。换句话说:

    while (j<MAX_LENGTH && (argv[j++]=strtok(NULL,DELIMS))!=NULL);
    

    输入您的代码并完成调试后,我发现传递给函数的字符串中只有一个单词。事实证明这是因为strtok 发生在main 中以检查cd/exit。这会在第一个单词的末尾留下 nul 字符,这是strtok 工作方式固有的效果。

    可能最快的解决方法是在 main 中的初始 strtok 之前复制字符串 ,然后将 that 传递给函数。换句话说,使用strdup(以及后来的free)。现在 glibc strdup,但是,如果您处于没有的环境(它是 POSIX 而不是 ISO),请参阅 here

    【讨论】:

    • 是的,你是对的。我错过了最后的strtok。我纠正了这个错误,但问题仍然存在。
    • @user2965601:当你打印出参数时,你看到了什么?在修复之前和之后。这是答案的症结所在,是调试实际问题的最佳方法。
    • 我使用 while 循环将 line[] 的内容复制到另一个数组中。它似乎正在工作。我还应该使用 strdup 吗?
    • @user2965601,是的,你应该这样做。通常,您应该更喜欢使用语言功能而不是自己编写代码。这样你会更快地交付你的软件:-)
    • 我按照你说的做了。另外,感谢您的帮助。它有很大帮助。 :)
    【解决方案2】:

    错误在main()

    您正在使用strtok 来查找该行的第一个单词。但是strtok 修改了该行,使其实际上只包含该单词(NUL 终止符被写入紧随其后的字符串)。

    您需要复制该行,或使用strtok_s,或执行其他操作以避免修改该行。

    【讨论】:

    • 要明确如果“line”包含“hello world”,当你strtok line时它会变成“hello\0world”,所以当你将line传递给exec_cmd时,它会被解释为一个只包含“hello”的字符串"。
    • 你是对的。这是造成问题的原因。伙计们,如果没有你们,我不会看到这一点。谢谢! :)
    • @Duck:就在之前,我尝试将其打印出来,但没有成功。你能告诉我如何正确打印吗?
    • 不确定您要打印的内容。 printf("%s\n",line); 之前和之后strtok 看到这个。
    • 或者更好,printf("[%s]\n",line); 这样您就可以更轻松地查看无关的换行符。
    猜你喜欢
    • 2012-09-28
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 2011-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多