簡體   English   中英

Unix Shell在C中實現Cat-文件描述符問題

[英]Unix Shell Implementing Cat in C - File Descriptor Issue

我已經完成了Unix shell的實踐實現,除了在cat輸出到文件時實現cat 存在問題 IE: cat foo.txt > bar.txt foo的內容輸出到bar

讓我們從主要功能開始,然后定義子方法:

int main(int argc, char **argv)
{           
    printf("[MYSHELL] $ ");

    while (TRUE) {
        user_input = getchar();
        switch (user_input) {

            case EOF:
                exit(-1);

            case '\n':
                printf("[MYSHELL] $ ");
                break;

            default:
                // parse input into cmd_argv - store # commands in cmd_argc
                handle_user_input();

                //determine input and execute foreground/background process
                execute_command();
        }
        background = 0;
    }
    printf("\n[MYSHELL] $ ");
    return 0;    
}

handle_user_input只是填充cmd_argv數組以執行user_input ,如果用戶希望輸出到文件,則刪除>並設置output標志。 這就是這種方法的本質:

while (buffer_pointer != NULL) { 
        cmd_argv[cmd_argc] = buffer_pointer;
        buffer_pointer = strtok(NULL, " ");

        if(strcmp(cmd_argv[cmd_argc], ">") == 0){
            printf("\nThere was a '>' in %s @ index: %d for buffer_pointer: %s \n", *cmd_argv,cmd_argc,buffer_pointer);
            cmd_argv[cmd_argc] = strtok(NULL, " ");
            output = 1;
        }

        cmd_argc++;

        if(output){
            filename = buffer_pointer;
            printf("The return of handling input for filename %s =  %s + %s \n", buffer_pointer, cmd_argv[0], cmd_argv[1]); 
            return;
        }        
}

然后調用execute_command ,解釋現在填充的cmd_argv 只是為了讓您了解大局。 顯然,這些情況都不匹配,並且調用create_process方法:

int execute_command()
{
    if (strcmp("pwd", cmd_argv[0]) == 0){
        printf("%s\n",getenv("PATH"));  
        return 1;
    }
    else if(strcmp("cd", cmd_argv[0]) == 0){
        change_directory();
        return 1;        
    }
    else if (strcmp("jobs", cmd_argv[0]) == 0){
        display_job_list();
        return 1;   
    }
    else if (strcmp("kill", cmd_argv[0]) == 0){
        kill_job();
    }
    else if (strcmp("EOT", cmd_argv[0]) == 0){
        exit(1);
    }
    else if (strcmp("exit", cmd_argv[0]) == 0){
        exit(-1);
    }
    else{
        create_process();
        return;
    }
}

很簡單吧?


create_process是我遇到問題的地方。

void create_process()
{
    status = 0;
    int pid = fork();
    background = 0;

    if (pid == 0) {
        // child process
        if(output){
            printf("Output set in create process to %d\n",output);
            output = 0;
            int output_fd = open(filename, O_RDONLY);
            printf("Output desc = %d\n",output_fd);
            if (output_fd > -1) {
                dup2(output_fd, STDOUT_FILENO);
                close(output_fd);
            } else {
                perror("open");
            }
        }
        printf("Executing command, but STDOUT writing to COMMAND PROMPT instead of FILE - as I get the 'open' error above \n");
        execvp(*cmd_argv,cmd_argv);
        // If an error occurs, print error and exit
        fprintf (stderr, "unknown command: %s\n", cmd_argv[0]);
        exit(0);
    } else {
        // parent process, waiting on child process
            waitpid(pid, &status, 0);
        if (status != 0)
            fprintf  (stderr, "error: %s exited with status code %d\n", cmd_argv[0], status);
    }
    return;
}

我打印的output_fd = -1 ,我設法在else perror("open")得到perror("open")open: No such file or directory 然后,當我顯示到控制台時,它會打印出它是"writing to COMMAND PROMPT instead of FILE" 然后執行處理cat foo.txt execvp ,但將其打印到控制台而不是文件。

我意識到此時不應該這樣做,因為不希望output_fd = -1並且應該返回另一個值; 但是我無法弄清楚如何正確使用文件描述符,以便通過cat foo.txt > bar.txt打開一個新文件/現有文件並寫入文件,就像回到命令行的stdin一樣。

我已經設法輸出到文件,但是隨后又丟失了正確的標准輸入。 有人可以把我引導到這里嗎? 我覺得我正在做一些愚蠢的事情,我做錯了或正在尋找。

非常感謝任何幫助。

如果要寫入文件,為什么要使用O_RDONLY? 我的猜測是您應該使用類似以下內容的方法:

int output_fd = open(filename, O_WRONLY|O_CREAT, 0666);

(0666用於在創建時設置訪問權限)。

顯然,如果您無法打開某個目標文件,則不應啟動該命令。

首先,我注意到的很明顯的事情是您已經打開了文件O_RDONLY。 輸出效果不好!

其次,重定向輸出的基本過程是:

  • 打開文件進行寫入
  • dup stdout,因此您可以根據需要保留副本。 如果重定向,則與stderr相同。
  • fcntl您的副本到CLOEXEC(或者,使用dup3)
  • dup2文件到stdout
  • 執行命令

最后,您真的將命令名作為全局變量傳遞了嗎? 我認為,一旦您嘗試實施cat foo | ( cat bar; echo hi; cat ) > baz就會再次困擾您cat foo | ( cat bar; echo hi; cat ) > baz cat foo | ( cat bar; echo hi; cat ) > baz或諸如此類。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM