-2

私はシェル プログラムを作成しています。値を に渡すときexecv()は、プログラムの名前 (これはls) への char ポインターが必要であり、引数の char ポインターの配列の配列へのポインターが必要です。

ユーザーの入力を調べて解析し、入力するとls、出力すると「ls」char *が出力されます。printf()したがって、行を正しく解析し、正しい情報を保存しています。これを に渡すとexecv()、パス名が正しくないと表示されますが、ポインタを手動で に変更するprogs[0] = "ls"と機能します。2 つの文字列 を比較するとstrcmp(mypointer, "ls")、 mypointer は を出力しますが"ls"、 と同等ではないことがわかります"ls"

誰かが理由を知っていますか?

ここに私のシェルプロセスコードがあります:

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

char **progs;
char ***arguments;
char **mode;
char pathname[] = "/bin/";

int main(int argc, char ** argv){

//printf("\n %s \n", progs);
//fflush(stdout);

char buff[100];
FILE *p;

p = fdopen(0, "r");  //opens FD 0 (Stdin) as a stream

char * pathname;

while(1){

    //printf("I'm at the top");

    if(isatty(1) == 1){ //check to see if stdout is going to the terminal
    printstart();       //if so, print 
    }

    fgets(buff, 100, p); // Gets the input from the stdin and puts it in buff

    int processid = fork();  //fork into child to complete task

    if(processid == 0){

        //initialize all variables

        int numcmd = countcmd(buff);
        int pipes = countpipes(buff);
        int i;
        int j;

        //allocate memory for tokenization

        progs = malloc(numcmd * sizeof(char *));
        arguments = malloc((numcmd) * sizeof(char *));
        mode = malloc((numcmd*2) * sizeof(char *));

        for(i = 0; i < numcmd; i++){
            progs[i] = malloc(10* sizeof(char *));
            mode[i] = malloc(10 * sizeof(char *));
            mode[2*numcmd-1-i] = malloc(10 * sizeof(char*));
            arguments[i] = malloc(15 * sizeof(char *));
                for(j = 0; j < 15; j++){
                arguments[i][j] = malloc(15 * sizeof(char*));
                }
            }

        /////////////////////////////////////////////////////////////////////

        parse(buff); //parses input and places it in the static progs

        for(i = 0; i < 1; i++){

        printf("\n This is progs %s", arguments[0][0]);

        char temp[25];
        //strcpy(temp, "/bin/");
        strcpy(temp, progs[0]);
        //strcat(temp, ' \0');

        //*progs = "ls";
        char * ptr = progs[0];
        for(;*ptr != '\0';){
            printf("This is what pointer poitns to %c \n", *ptr++);
            }
        printf("This is the program: <<%s>>", progs[0]);
        fflush(stdout);
        char * argument[2];
        argument[0] = "ls";
        argument[1] = '\0';
        char * hell = "l\0";

        printf("This is the value of comparison %d\n", strcmp(progs[0], hell));

        char **temparg = arguments[0];
        //char temp[20] = progs[0];

        errno = 0;
        execvp("ls", *argument);

        char * error = strerror(errno);
        printf("This is the error %s", error);
        return;
        }

    }       
        else{
        int status;
        waitpid(processid, &status, WIFEXITED(status));

        }
}

return 0;
}

ここに私の parse() コードがあります:

#include <string.h>
#include <stdio.h>
#include "myshell.h"

int parse(char * buff){

//Initialize all variables and pointers
int cmd = 0;
int argument = 0;
int mod = 0;
int j = 0;
int hitargs = 0;
int gotcommand = 0;
int multiarg = 0;

char ** argptr = arguments[cmd];
char * ptr1 = progs[cmd];
char * argptr2 = argptr[argument];
char * ptr2 = mode[mod];

while(buff[j] != '\0'){

    switch(buff[j]){

        case ';':
            cmd++;
            argument = 0;
            multiarg = 1;
            *argptr2++ = '\0';

            argptr = arguments[cmd];
            argptr2 = argptr[argument];
            ptr1 = progs[cmd];

            *ptr2 = buff[j];
            mod += 2;
            ptr2 = mode[mod];

        case ' ':
            if(gotcommand == 0){
            break;
            }
            else{
                if(hitargs == 0){
                hitargs = 1;
                *ptr1++ = '\0';
                argument++;
                argptr2 = argptr[argument];
                }
                else{
                argument++;
                argptr2 = argptr[argument];
                }
                break;
            }
        default:
            if(gotcommand == 0){
                *ptr1++ = (char) buff[j];
                *argptr2++ = buff[j];
                gotcommand = 1;
            }
            else if(gotcommand == 1 && hitargs == 0){
                *ptr1++ = (char) buff[j];
                *argptr2++ = buff[j];
            }
            else if(gotcommand == 1 && hitargs == 1){
                *argptr2++ = buff[j];
            }
    }

j++;
}

*argptr2++ = '\0';
*ptr1++ = '\0';

int cmdflag = 0;
int spaceflag = 0;
int argflag = 0;
int cmdct = 1; //account for null
int argumentct = 1; //account for null termination

return 1;
}

ランダムな printf ステートメントで申し訳ありません。

4

2 に答える 2

2
  • メイン プログラムにはmyshell.h、解析コードと同じようにインクルードする必要があります。
  • 不足している関数があると便利です ( countcmd()and などcountpipes()— 名前から少し推測できますが、それらが何をするのか正確にはわかりません)。
  • <unistd.h>メインプログラムに含める必要があります。
  • 宣言されていない関数 ( などfork()) に関する警告が表示されているはずであり、これらの警告に注意して修正する必要があります。
    • これらの警告が表示されない場合は、コンパイルに警告オプションを追加する必要があります。
    • を使用する場合はgcc、 を使用-Wallするのが出発点として適しています。

警告を有効にすると、以下が表示されます。

shex.c:95: warning: passing argument 2 of ‘execvp’ from incompatible pointer type
shex.c:99: warning: ‘return’ with no value, in function returning non-void
  • return EXIT_FAILURE;後者は、またはで処理するのが最適exit(EXIT_FAILURE);です。
  • 前者は によってトリガーされexecvp("ls", *argument);ます。
  • 多くの引数を含むものには、複数形 (arguments?) を使用する方がよい場合があります。
  • ……そうか、グローバル変数ってあるんだなarguments
  • あなたは宣言しchar ***arguments;ます。 痛い! 私は時々トリプルポインターを使用しましたが、ごくたまにしか使用しませんでした。ほとんどの場合、これはポインターのレベルが多すぎるため、特にこの演習ではそうです。
  • 次に、ローカル変数もありますchar *argument[2];
  • したがって、正しい呼び出しは ですexecvp("ls", argument);

待機中のコードをすぐに展開して、少なくとも情報を出力します。

    else
    {   
        int status;
        int corpse = waitpid(processid, &status, WIFEXITED(status));
        printf("Command exited: PID = %d; status = 0x%.4X\n", corpse, status);
    } 

解析コードでは、 が にcase ';':ドロップしcase ' ':ます。それが意図的なものである場合は、それを文書化してください ( などのコメントを付けて/* DROP THROUGH */)。そうでない場合は、不足している改行を挿入します。あなたのdefault:ケースもおそらくその後休憩する必要があります。これはそれほど重要ではありませんが、従来どおりであり、新しいケースを処理する必要がある場合にドロップスルーから保護します.

の最後で宣言された 5 つの変数の文字列parse()は不要です。それらは決して使用されないローカル変数です (コンパイラーが教えてくれるように)。

の上部で次のmain()ことを行います。

FILE *p;
p = fdopen(0, "r");  //opens FD 0 (Stdin) as a stream

これは必要ありません。stdinは既にストリームとして開かれています。

pから(別名stdin) を読み取りますfgets()。全体として、これは良い (より良い) ですが、含まれていない改行が含まれてgets()いることに注意する必要があり、戻りステータスを確認する必要があります (何も読み取れない可能性があります)。以下も使用する必要があります。fgets()gets()sizeof()

if (fgets(buff, sizeof(buff), stdin) == 0)
    ...error - read failed...

メモリ割り当ては非常に複雑です。のような固定サイズの入力の場合char buff[100];、非動的割り当てを使用する余裕があります。引数は空白で区切られているため、合計で約 50 個を超える引数を指定することはできません。

等。

于 2012-04-15T22:57:03.327 に答える
0

コード全体を調べていないため、他のバグがある可能性がありますが、「ls」の問題に関しては、解析コードに次を追加する必要があります。

      while (buff[j] != '\0' && buff[j]  != '\n')

これにより、コマンドポインターに「改行」を追加しないことが保証されます*ptr1++ = (char) buff[j];

新しい行に遭遇した場合、 fgetsは読み取りを停止しますが、文字列の一部として含めることに注意してください。

于 2012-04-15T21:40:25.853 に答える