0

Mac OSX10.6.6とXCode3.2.4でいくつかのコードを実行していて、かなり標準的なコードがあります:fork()、pid == 0の場合、コマンドとargsを含むexecvp(argsにはコマンドが配列の最初の要素であり、配列はnullで終了します)。

これについては、オペレーティングシステムのクラスで説明します。割り当ては、単純なシェルを作成することです。リダイレクト(<と>)とパイプ(|)の両方の引数とスイッチを使用してコマンドを実行します。いくつか問題が発生しています。

1)デバッグ中にEXC_SOFTWARE信号を受け取ることがあります(これまでのところ、XCodeの外部でアプリを実行した場合は取得できませんが、Macを初めて使用するため、実行した場合にどのようになるかわかりません)

2)次のコマンドのgetlineが、他のcoutによって出力されたように見えるジャンクになることがあります。これは永遠にループし始め、指数関数的に壊れます。私はすべてのプロンプトでgetpid()を印刷してテストしましたが、最初のプロセスだけがこれらを印刷します。偶発的な「フォーク爆弾」はないようです。

これが私がこれまでに持っているものです:

#include <iostream>
#include <string>
#include <unistd.h>

using namespace std;

char** Split(char* buffer, int &count) {
    count = 1;
    for (int i = 0; i < strlen(buffer); i++) {
        if (buffer[i] == ' ') {
            count++;
        }
    }
    const char* delim = " ";
    char* t = strtok(buffer, delim);
    char** args = new char*[count + 1];
    for (int i = 0; i < count; i++) {
        args[i] = t;
        t = strtok(NULL, delim);
    }
    args[count] = 0;
    return args;
}

void Run(char** argv, int argc) {
    int pid = 0;
    if ((pid = fork()) == 0) {
        //for testing purposes, print all of argv
        for (int i = 0; i < argc; i++) {
            cout << "{" << argv[i] << "}" << endl;
        }
        execvp(argv[0], argv);
        cout << "ERROR 1" << endl;
        exit(1);
    } else if (pid < 0) {
        cout << "ERROR 2" << endl;
        exit(2);
    }
    wait(NULL);
}

int main(int argc, char * const argv[]) {
    char buffer[512];
    char prompt[] = ":> ";
    int count = 0;
    while (true) {
        cout << prompt;
        cin.getline(buffer, 512);
        char **split = Split(buffer, count);
        Run(split, count);
    }
}

それはまさに私が持っているものです、あなたはカット、ペースト、そしてビルドすることができるはずです。

私はC++が得意ではありません。削除しないとメモリリークが発生する可能性がありますsplitが、主な焦点はEXC_SOFTWAREシグナルであり、ループの問題で何が間違っているかを確認します。何かご意見は?

編集:

割り当てに必要なエラーチェックは非常に限られており、すべての入力が正しいと想定しています。正しいとは、アプリがコマンドを実行するために適切にフォーマットされ、制限されていることを意味します。つまり、奇妙なスペースカウント、非同期を実行する&、マルチパイピングコマンドなどはありません。

4

2 に答える 2

0

入力行にスペースよりも1つ多いトークンが含まれていると想定しています。入力行が空であるか、スペースで終了または開始するか、複数の連続するスペースが含まれている場合、この仮定は失敗する可能性があります。このような場合、strtokの呼び出しの1つがNULLを返し、Runでその引数を出力しようとすると、フォークされたプロセスがクラッシュします。これらは私が問題に遭遇した唯一のケースです。他の人に出会ったことがある場合は、入力内容を指定してください。

その仮定を回避するために、トークン化を行うのと同じ方法でstrtokを使用してカウントを行うことができます。これは一般的には良い考えです。2つのことを一致させる必要があり、同じ方法でそれらを実行できる場合、代わりに別の方法で実行すると、追加のエラーの原因が発生します。

于 2011-02-05T03:30:51.290 に答える
0

1つの問題は、からの戻り値をチェックしないことですcin.getline()。そのため、EOFと入力すると、コードはタイトループに入ります。また、メモリリークが発生しています。

試す:

while (cout << prompt && cin.getline(buffer, sizeof(buffer))
{
    int count = 0;
    char **split = Split(buffer, count);
    Run(split, count);
    delete[] split;
}

のコードは、Split()空白行をまったくうまく処理しません。引数がnullポインタのみの場合、実行にはaeonexecvp()が必要なようです。これは、空白行を返した場合に発生します。


複数の簡単なコマンドを実行できます(「vimmakefile」と「makeshell」と「ls-l」と「catshell.cpp」など。2つ以上の引数を使用していくつか実行しました)OKこれで、などでコマンド(シェル)を終了できControl-Dます。からの警告なしでコンパイルされるように修正しましたg++ -O -Wall -o shell shell.cpp。空の行またはすべての空白行を正しく処理するように分割コードを修正していません。

#include <iostream>
#include <string>
#include <unistd.h>

using namespace std;

char** Split(char* buffer, int &count) {
    count = 1;
    for (size_t i = 0; i < strlen(buffer); i++) {  // #1
        if (buffer[i] == ' ') {
            count++;
        }
    }
    char** args = new char*[count + 1];
    const char* delim = " ";
    char* t = strtok(buffer, delim);
    for (int i = 0; i < count; i++) {
        args[i] = t;
        t = strtok(NULL, delim);
    }
    args[count] = 0;
    return args;
}

void Run(char** argv, int argc) {
    int pid = 0;
    if ((pid = fork()) == 0) {
        //for testing purposes, print all of argv
        for (int i = 0; i < argc; i++)
        {
            if (argv[i] != 0)  // #2
                cout << "{" << argv[i] << "}" << endl;
            else
                cout << "{ NULL }" << endl;  // #3
        }
        execvp(argv[0], argv);
        cout << "ERROR 1" << endl;
        exit(1);
    } else if (pid < 0) {
        cout << "ERROR 2" << endl;
        exit(2);
    }
    wait(NULL);
}

int main(int argc, char * const argv[]) {
    char buffer[512];
    char prompt[] = ":> ";
    while (cout << prompt && cin.getline(buffer, sizeof(buffer)))  // #4
    {
        int count = 0;
        char **split = Split(buffer, count);
        if (count > 0)  // #5
            Run(split, count);
        delete[] split;  // #6
    }
}

重要な変更をマークしました(ほとんどの場合、それほど大きくはありません)。MacOSX10.6.6でGCC4.2.1をコンパイルしています。

バッファに表示されているガベージ文字を簡単に説明することはできません。

于 2011-02-05T03:39:31.107 に答える