使用strtok()并在后台执行UNIX命令

时间:2013-09-20 18:23:49

标签: c unix background strtok

我正在尝试编写一个创建UNIX shell的C程序。在这个shell中,当键入UNIX命令时,shell应该在前台或后台执行它(当指定&时,后台)。我正在获取在前台运行的命令,但我不能在后台运行它。 这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

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

int main(int argc, char *argv[])
{
    char *cmd, *bg;
    char line[MAX_LENGTH];
    pid_t fpid,bpid;
    int status;
    while (1)
    {
           fpid=10;
           bpid=10;
            printf("myshell > ");
            if (!fgets(line, MAX_LENGTH, stdin))
                    break;
             int j=0;

            if(cmd = strtok(line, DELIMS))
            {

                    bg = strtok(line," ");
                    while(bg!=NULL)
                    {
                            printf("%s",bg);
                            bg = strtok(NULL, " ");
                            if(strcmp(bg, "&") == 0)
                                    break;
                    }

                    printf("%s", bg);
                    if(strcmp(cmd,"exit")==0)
                            break;

                    else if(strcmp(bg,"&")==0)
                    {
                            bpid=fork();
                            //waitpid(bpid,&status,0);
                            system(line);
                            exit(0);
                    }
                    else
                   {
                            //fpid=fork();
                            //if(fpid==0)
                            //{
                                    system(line);
                            //      exit(0);
                            //}
                            //else 
                            //{
                            //      waitpid(fpid,&status,0);
                            //}
                    }
            }
    }

  return(0);
}

有人可以在这个计划中帮助我吗?我的作业真的需要这个。

2 个答案:

答案 0 :(得分:1)

阅读fork()的联机帮助页。返回码0表示您在孩子中,非零(非负)表示您是父母。您应该基于此使用不同的逻辑,并在子分支中使用system()(或更好的exec*()

这是你应该拥有的典型逻辑:

tokenize(line)

if (last token is '&') {
    rc = fork();

    if (rc < 0)
        handle error;

    else if (rc > 0) {  /* in parent, rc = child pid */
        do whatever you planned to do in the parent process
    }
    else {  /* in child */
        use exec*() to start the child command
    }
}
else {  /* foreground execution */
    use system() to run command
}

答案 1 :(得分:0)

以下是从问题中的代码派生的代码,该代码发出提示,获取输入行,将其拆分为令牌,检测到最后一个令牌是&,并检测到第一个单词是{{ 1}}并退出循环。它仔细地打印出它的发现。而你现在需要处理fork,exec,wait等代码。

exit

请注意,代码不会阻止您在一行中输入太多令牌。它最终通过#include <assert.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define MAX_LENGTH 1024 #define DELIMS " \t\r\n" int main(void) { char line[MAX_LENGTH]; char *ps1 = "toysh> "; while (fputs(ps1, stdout) > 0 && fgets(line, sizeof(line), stdin) != NULL) { char *cmd[100]; char *bg = NULL; int j = 0; char *tokens = line; while ((cmd[j++] = strtok(tokens, DELIMS)) != NULL) tokens = NULL; assert(j < 100); /* The line has been tokenized into j-1 tokens */ /* Print the tokens found */ for (int i = 0; i < j; i++) { if (cmd[i] != 0) printf("%d: <<%s>>\n", i, cmd[i]); else printf("%d: NULL pointer\n", i); } assert(j > 0); if (j == 1) continue; // No command j--; assert(j > 0); if (strcmp(cmd[j-1], "&") == 0) { printf("== Found &\n"); bg = cmd[j-1]; cmd[--j] = 0; if (j == 0) { puts("Syntax error: cannot have & on its own"); continue; } } if (strcmp(cmd[0], "exit") == 0) { printf("== Found exit command\n"); if (bg != NULL) { puts("Can't run exit in background"); continue; } break; } /* ** Now you can do your fork, exec, waitpid work. Note that the ** command is already split into words with the null pointer at ** the end. This is what execv(), execve() and execvp() want */ } putchar('\n'); return(0); } 检测到你已经这样做了,如果它还没有崩溃的话。你需要在某些时候做出防弹。

要求进一步协助

  

我对fork和waitpid工作很新。你能帮帮我吗?

在另一个答案中,你得到了很好的建议。

添加:

assert

添加:

#include <sys/wait.h>

添加:

static void run_command(char **argv, int bg_flag);

新功能:

        /*
        ** Now you can do your fork, exec, waitpid work.  Note that the
        ** command is already split into words with the null pointer at
        ** the end.  This is what execv(), execve() and execvp() want
        */
        run_command(cmd, (bg != NULL));

你可以决定你的shell应该是多么冗长,但是当你调试它时,更多的信息要好于更少。

此外,错误消息应全部转到static void run_command(char **argv, int bg_flag) { pid_t pid; fflush(0); // Flush pending output if ((pid = fork()) < 0) printf("Fork failed\n"); else if (pid > 0) { /* Parent shell */ if (bg_flag == 0) { int status; int corpse; while ((corpse = waitpid(-1, &status, WNOHANG)) >= 0) { if (corpse != 0) printf("Process %d exited with status 0x%.4X\n", corpse, status); if (corpse == 0 || corpse == pid) break; } } else printf("%d: %s running in background\n", pid, argv[0]); } else { /* Child process */ execvp(argv[0], argv); fprintf(stderr, "%d: failed to execute %s (%d: %s)", (int)getpid(), argv[0], errno, strerror(errno)); exit(1); } } ;我给stderr留下了一个公平的数字。