简体   繁体   中英

child process shell in linux

I am about to finish my class project which consists of making a shell that executes the commands in /usr/bin/. If the user mistypes the command, the shell suggests similar commands using hamming techinique. All of this is already done.

When the user enters a command correctly, the shell executes perfectly with no problem. The problem is when the command doesn't exist. In that case, I create a vector of the candidate commands, which have a Hamming weight <= 1 (that is, they differ from the user's input by no more than 1 character). Then I ask the user which of the commands to execute

For example, if the user types sipnote I suggest zipnote . If the user inputs 'y' to execute the command, it executes perfectly. The problem occurs afterward, when the execution finishes: it comes back to the top of the routine and for some reason enters the for beyond the routine. As you can see at the top of the routine, I put a comment in the else where the issue occurs.

The problem is that, for example, if the user types sipnote I suggest zipnote and he inputs y meaning he wants to execute the command suggested. The command is executed, it returns to the top of the whole routine, BUT it prints then:

"Ingrese su comando" ("Enter your command") and then "Quizo decir [y/n]" ("Did you mean"), which is inside the for look, asking the user to choose one of the candidates.

I have no idea why this is happening. What I want to happen is to choose candidate, execute it, then return to the top and start all over again.

Sorry for the long question and bad English, it's not my native language :P

int main()
{
    cout << "comienza rutina" < <endl;
    while(1)
    {
        cout << "entra a while" << endl;
        // First, load the commands from /usr/bin into memory and save them
        // in a vector.
        string directorio = string("/usr/bin/");
        vector<string> files = vector<string>();
        conseguirComandos(directorio,files);

        char path[80];
        char comando[80];        
        char delims[] = " ";
        char *result = NULL;

        char *argument[10];
        int i = 0;
        int k = 0;
        int child_pid,child_status; 

        int dist_hamming = 0;
        vector<string> candidatos = vector<string>();
        char resp[1];

        strcpy (path,"/usr/bin/");

        // "Enter your command."
        cout << "Ingrese su comando" << endl;
        fgets(comando,80,stdin);
        quitar_espacio(comando); 

        if (existe_comando(comando, files) == true)
        {
            result = strtok(comando, delims);

            // Split the user's command on spaces and store each word individually
            // in the argument array.  The system call execv receives the array of
            // char pointers as its second argument.
            while (result != NULL) {
                argument[i] = result;
                i++;
                result = strtok( NULL, delims );
            }

            unir_path_comando(path,argument);
            argument[i] = (char*)0; // Last element must be char *NULL, per execv docs

            char *direccion;
            direccion = path;

            if ((child_pid = fork()) != 0)
            {
                // "Parent is waiting"
                cout << "Padre espera" << endl;
                wait(&child_status);
            } else {    
                // Child process executes the user's command
                cout << "Hijo ejecuta" << endl;
                execv(path, argument);
                //exit(1);
            }
        }
        else // problem is in this section
        {
            int indice = 0;
            int condicion = 0;
            int size_cadena = 0;
            string comando_ejecutar;
            for (int i = 0; i < files.size(); i++)
            {
                if (hamming(comando, files[i]) <= 1)
                {
                    // cout << "candidato: " << files[i] << endl;
                    candidatos.push_back(files[i]);
                }
            }

        if (candidatos.size()!=0)
        {
            for (int i = 0; i < candidatos.size(); i++)
            {
                cout << "Quizo decir: " << candidatos[i] << " " << "[Y/N]"<<endl;
                scanf("%s", resp);

                if (resp[0] == 'Y' || resp[0] == 'y')
                {
                    indice = i;
                    break;
                }
            }

            // Length of the string containing the suggested command.
            size_cadena = candidatos[indice].length();
            // Store a pointer to the command to execute.
            comando_ejecutar = candidatos[indice];
            // Copy the selected command to a string.
            int m = 0;
            for (int j = 0; j < size_cadena; j++)
            {
                m++;
                comando[j] = comando_ejecutar[j];
            }
            comando[m] = 0;

            result = strtok( comando, delims );         

            //se hace un split al comando ingresado por el usuario como delimitador--> " ". Con el fin de tener cada argumento
            //en una casilla distina en el arreglo argument. Ya que el system call execv recibe como segundo parametro un arreglo 
            //de apuntadores a chars conteniendo los parametros del comando.
            int z = 0;
            while( result != NULL ) {
                argument[z] = result;
                z++;
                result = strtok( NULL, delims );
            }
        // Docs say the final argument to execv must be NULL.
        argument[z] = (char*)0;
        strcpy (path,"/usr/bin/");
        unir_path_comando(path,argument);
        char *direccion;
        direccion = path;

        if ((child_pid = fork()) != 0)
        {
            // "Parent is waiting"
            cout<<"Padre espera"<<endl;
            wait(&child_status);
        }
        else
        {   
            // Child executes the user's command.
            cout<<"Hijo ejecuta"<<endl;
            execv (path, argument);
            //exit(1);
        }
        }
        else
        {
            // No candidates to suggest.
            cout << "No tengo nada que mostrar" << endl;
        }
    }   
}
return 0;
}

scanf("%s",resp) reads from stdin until the user enters whitespace.

If the user types Y<enter> then scanf reads the Y but does not read the <enter> .

When you return to the top of the loop you call fgets(comando,80,stdin) which immediately reads the <enter> that scanf left behind and returns an empty string. An empty string isn't a valid command, so you then prompt Quizo decir [y/n] again.

If you replace scanf with fgets it should work OK.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM