Unix / C ++代码,用于读取文本行,将其分解为单词,并运行结果

时间:2016-09-22 07:14:00

标签: c++ c shell unix

程序应该执行一些循环:

  1. 发出提示并阅读一行文字。

  2. 将该行分解为单词。

  3. 如果命令是内置命令,请自行处理,然后返回读取步骤。否则,

  4. 执行fork以创建新进程。报告任何失败的原因(当然,如果分支失败,请不要执行。)

  5. 子进程将列表中的第一个单词视为命令的名称,并使用exec调用运行它。将整个列表作为参数发送到程序。报告任何失败的原因。

  6. 父进程等待子进程退出,然后报告其状态。

  7. 返回读取下一个命令。

  8. 我在下面写下了头部,身体和实现

    这是行解析类:

     #include <string>
    
    using namespace std;
    
    /*
     * This class takes a C++ string and provides an array of plain C strings
     * (array of pointers to char) representing the words in the line.
     */
    
    class LineBreaker {
    public:
            // Construct the object, providing the line of text to be
            // broken up.
            LineBreaker(const string &s);
    
            // Clean up.
            ~LineBreaker() {
                    delete [] m_data;
                    delete [] m_parmlist;
            }
    
            // Return an pointer to the first slot of an array of pointers
            // containing the words in the string sent to the constructor.
            // The list is terminated with a NULL pointer.
            char **parmlist() { return m_parmlist; }
    private:
            char *m_data;           // Dyn array of characters from the string.
            char **m_parmlist;      // Array of words
    };
    

    这是跑步者计划,是身体:

        /*
         * Simple program to demonstrate the fork/exec/run sequence for creating
         * processes in Unix.
         */
    
        #include <iostream>
        #include <string>
        using namespace std;
    
        #include <unistd.h>
        #include <stdlib.h>
        #include <string.h>
        #include <sys/types.h>
        #include <sys/wait.h>
    
        #include "linebreaker.h"
    
    main()
    {
            /* Ask for a program to run.  This is just the file name of an
               executable. */
            cout << "Your command? ";
            string cmd;
            getline(cin, cmd);
    
            LineBreaker breaker(cmd);
    
            /* Create a child process and try to run the program in it. */
            if(fork() == 0) {
                    execv(breaker.parmlist()[0], breaker.parmlist());
                    cout << "Sorry, the exec failed." << endl;
                    exit(1);
            }
    
            /* See what was the cause of the child processes' demise. */
            int status;
            wait(&status); /*we only need to change this part, and use something like this if(string(breaker.parlist()[0]) == "exit") */
            if(WIFEXITED(status)) cout << "Exited." << endl;
            else if(WIFSIGNALED(status)) cout << "Killed." << endl;
            else cout << "Mysteriously vanished." << endl;
    }
    
    /*
     * Note: This program really should check the return values for fork() and for
     * exec() to make sure they succeeded, and print an error message if not.
     * Failure is indicated by a negative return value.  It would also help to use
     * errno and strerror() to print a descriptive error message in place of the
     * existing exec() failure message, or for the new messages.
     *
     * It also uses uses gets() and fixed-size buffers, which creates a risk of
     * buffer overflow.
     */
    

    这是实施:

    #include <string>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    #include <list>
    
    #include "linebreaker.h"
    
    LineBreaker::LineBreaker(const string &s)
    {
            // Copy the string as a character array.
            m_data = new char[s.length()+1];
            strcpy(m_data, s.c_str());
    
            // Find all the words.
            char last = ' ';
            list<char *> parts;
            for(char *scan = m_data; *scan; ++scan) {
                    char curr = *scan;
    
                    if(isspace(last) && !isspace(curr))
                            parts.push_back(scan);
                    else if(!isspace(last) && isspace(curr))
                            *scan = '\0';
    
                    last = curr;
            }
    
            // Allocate the array of pointers for exec, and copy the
            // pointer into it.  Then add the NULL terminator.
            m_parmlist = new char * [parts.size()+1];
            copy(parts.begin(), parts.end(), m_parmlist);
            m_parmlist[parts.size()] = NULL;
    }
    

    我想在while循环中包含现有运行程序的大部分代码,以便它会重复读取和执行命令,而不是读取并退出。

    在跑步者程序中,输入空行会产生错误(执行失败)。更改程序,以便输入一个空行(没有单词,因此没有命令名称),不运行任何命令,但程序只返回提示然后读取另一个命令。

    此版本在常用位置搜索命令文件,因此不必查找要执​​行的文件的完整路径。跑步者计划使用execv;只需用execvp替换。

    检查每个fork,exec或wait调用的返回码以检查是否有失败。我想使用errno和strerror来打印一条消息,说明失败的原因。实现两个无法使用fork / exec运行的命令。这些是exit命令和cd命令。这些是shell必须自己执行的内置命令。对于状态报告,如果程序以0以外的代码(错误退出)退出,或者如果崩溃,则报告该情况。对于正常退出,什么都不说。报告退出代码或崩溃原因。更多内容如下。

1 个答案:

答案 0 :(得分:0)

不是一个完整的答案,因为这是作业,但这里有一个提示:while (std::getline( std::cin, cmd ))

这是有效的,因为getline()返回对输入流的引用,当您将其转换为bool值时,它将返回true,而流尚​​未遇到结束文件或错误。