简体   繁体   中英

How to run a program from terminal input(linux)?

While I think I have the grasp on how fork() , exec() , wait() and pid work in C, I have yet to find a way how to run a personal program from within a program.

Here's my code:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h> /* for fork() */
#include<sys/types.h> /* for pid_t */
#include<sys/wait.h> /* fpr wait() */

int main(int argc, char* argv[])
{
    char  fileName[255];
    pid_t pid;

    switch (pid = fork()) {
    case -1: //Did not fork properly
        perror("fork");
        break;

    case 0: //child
        execv(fileName[0],fileName);

        puts("Oh my. If this prints, execv() must have failed");
        exit(EXIT_FAILURE);
        break;
    default: //parent
        //Infinite Loop
        while (1) {
            printf(" %s > ", argv[0]);
            scanf("%s", fileName); // gets filename
            if (fileName[0] == '\0') continue;
            printf("\n Entered file: %s",fileName); // prints the fileName
            waitpid(pid,0,0); /* wait for child to exit() */
            break;
        }
    }

    return 0;
}

My questions are the following:

  1. I want to take a string as an input and I want to limit its scope to 255 characters. Is char fileName[255] and then scanf("%s", fileName); the way to go? Should I use getLine() or some other function instead?

  2. Let's say that the input is taken correctly. How do I execute say an existing hello world program. Will the input be stored in *argv[] ? I found out that in a different program I could use

     static char *argv[] = { "echo", "Foo is my name." , NULL }; execv("/bin/echo", argv); 

    in order to echo "Foo is my name.". Can I do something similar with a helloWorld program?

You're passing a single character as the command name, and the name string as the start of a list of arguments — as if the prototype for execv() were int execv(char cmd, char *args) .

The actual prototype is: int execv(char *cmd, char **args) , so you need:

char *args[2] = { fileName, 0 };

execv(args[0], args);

I assume you set fileName to a meaningful value somewhere — that isn't shown. For example, it might be "./local_program" . It will be treated as the pathname of the executable.

If you want to read the name, then you can use fgets() or getline() , but you'll need to remove the newline:

if (fgets(fileName, sizeof(fileName), stdin) != 0)
{
    fileName[strcspn(fileName, "\n")] = '\0';
    …as before…
}

or:

char *fileName = 0;
size_t length = 0;
if (getline(&fileName, &length, stdin) != -1)  /* Not EOF! */
{
    fileName[strcspn(fileName, "\n")] = '\0';
    …as before…
}
free(fileName);

The use of strcspn() avoids having to special case overly long command lines such that there isn't a newline in the fileName . Note that this does not attempt to split the input line into a command name and arguments at spaces or anything fancy like that. That's the next level of shell implementation:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(void)
{
    char fileName[256];
    if (fgets(fileName, sizeof(fileName), stdin) != 0)
    {
        fileName[strcspn(fileName, "\n")] = '\0';
        char *args[129];
        char **argv = args;
        char *cmd = fileName;
        const char *whisp = " \t\f\r\b\n";
        /* Ugh — strtok()?  OK while only handling white space separators */
        char *token;
        while ((token = strtok(cmd, whisp)) != 0)
        {
            *argv++ = token;
            cmd = 0;
        }
        *argv = 0;

        execv(args[0], args);
        fprintf(stderr, "Oops!\n");
    }
    return 1;
}

I don't need to check for overflow of the args array because 256 characters of input, minus terminating null, cannot be split to produce more than 128 single-character arguments, each separated from the adjacent ones by a single white space character. Using strtok() is a temporary band-aid. As soon as you need to deal with real shell syntax (pipes, I/O redirections, quoted strings with spaces, etc), strtok() is woefully the wrong tool. (It — strtok() — is also the wrong function to use in any library function whatsoever. Use POSIX strtok_r() on Unix or Microsoft's strtok_s() on Windows if you must use a strtok() -like function in library code.)

As it stands, you'll need to fix the compilation errors from your code:

g++ -std=c++11 -g -Wall -Wextra -Wwrite-strings     36501711.cpp   -o 36501711
36501711.cpp: In function ‘int main(int, char**)’:
36501711.cpp:18:25: error: invalid conversion from ‘char’ to ‘const char*’ [-fpermissive]
         execv(fileName[0],fileName);
                         ^
36501711.cpp:18:35: error: cannot convert ‘char*’ to ‘char* const*’ for argument ‘2’ to ‘int execv(const char*, char* const*)’
         execv(fileName[0],fileName);
                                   ^
36501711.cpp: At global scope:
36501711.cpp:7:5: warning: unused parameter ‘argc’ [-Wunused-parameter]
 int main(int argc, char* argv[])
     ^

The warning (about unused argc ) is harmless, but the errors are real, and need to be fixed.

You need to initialise fileName before you fork, otherwise the child won't have any valid data there:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h> /* for fork() */
#include<sys/types.h> /* for pid_t */
#include<sys/wait.h> /* fpr wait() */

int main(int argc, char* argv[])
{
    char  fileName[255];
    pid_t pid;

    //Infinite Loop
    while (1) {
        printf(" %s > ", argv[0]);
        scanf("%s", fileName);
        if (fileName[0] == '\0')
            break;
        printf("\n Entered file: %s\n", fileName);

        pid = fork();
        switch (pid) {
        case -1: //Did not fork properly
            perror("fork");
            break;

        case 0: //child
            execl(fileName, fileName, 0);
            perror("exec");
            exit(EXIT_FAILURE);
            break;

        default: //parent
            waitpid(pid,0,0); /* wait for child to exit() */
            break;
        }
    }

    return EXIT_SUCCESS;
}

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