简体   繁体   中英

Separating and executing command line arguments using execvp()

The code below works fine for what it does. I enter any 2 commands, in this case ls and pwd, and the terminal outputs the result of those commands, plus the PID for the child that ran it.

Command line looks like this currently: ./practice.c ls pwd

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

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

   long cpid1, cpid2;

   switch(cpid1 = fork()){
      case -1:
         perror("fork failed");
         return EXIT_FAILURE;

      case 0:
         printf("First child, pid=%d, executing command...\n", getpid());
         execvp(argv[1], NULL);
         return EXIT_FAILURE;
   }

   wait(NULL);
   switch(cpid2 = fork()){
      case -1:
         perror("fork failed");
         return EXIT_FAILURE;
      
      case 0:
         printf("Second child, pid=%d, executing command...\n", getpid());
         execvp(argv[2], NULL);
         return EXIT_FAILURE;
   }

   while(wait(NULL) != -1);
   return EXIT_SUCCESS;

}

However, I want the user to enter a command line that looks more like this: ./practice.c pwd, ls -l

So, first of all my problem is separating out the command line. "PWD" would be argv[1], then "," would be argv[2], then "ls" would be argv[3] and so on. What I really want is to use the commas as delimiters. Even then, in the case of "ls -l" I want that to be 1 arg so when I run exec it will look like all I did was run execvp("ls", "-l", NULL). Any tips or tricks you recommend?

Transferring some comments into an answer.

Note that you'd have something like:

char *args[3] = { "ls", "-l", NULL };

(with the values deduced from argv — and you'd need to size args[] based on the number of arguments before or after the argument containing comma ( , ) only), and then invoke execvp(args[0], args); . The notation you show for the call to execvp() would be applicable to execlp() , but only when you know the number of arguments at compile time. In your revised requirement, you don't know the number of arguments at compile time, which is why you need to use execvp() .

Your existing code gives the invoked program no arguments. That's not recommended. Again, you should create an array and use that:

char args[2] = { argv[1], NULL };
…
execvp(args[0], args);

Similarly of course for argv[2] and the second command. With the revised requirements, you'll need to accumulate arguments up to the comma argument, then run it. You could find the index of the comma argument and replace that with NULL and work from there.

This code extracts the execution into a function, execute() , leaving the main() function to split the argument list, etc.

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

static void execute(char **args);

int main(int argc, char **argv)
{
    int arg1 = 1;
    for (int i = 1; i < argc; i++)
    {
        if (strcmp(argv[i], ",") == 0)
        {
            argv[i] = NULL;
            execute(&argv[arg1]);
            arg1 = i + 1;
        }
    }
    if (argv[arg1] != NULL)
        execute(&argv[arg1]);

    return EXIT_SUCCESS;
}

static void execute(char **args)
{
    pid_t pid;
    if ((pid = fork()) == -1)
    {
        perror("fork failed");
        exit(EXIT_FAILURE);
    }
    else if (pid == 0)
    {
        char **argv = args;
        while (*argv)
            printf("[%s]", *argv++);
        putchar('\n');
        printf("Child pid=%d executing command %s...\n", getpid(), args[0]);
        execvp(args[0], args);
        fprintf(stderr, "%d: failed to execute command %s\n", getpid(), args[0]);
        exit(EXIT_FAILURE);
    }
    else
    {
        int corpse;
        int status;
        while ((corpse = wait(&status)) != -1)
            printf("Child %d exited with status 0x%.4X\n", corpse, status);
    }
}

The program source is in vp13.c ; the program is vp13 . When run like this, it produces:

$ vp13 ls -l , pwd , ls -C -F , date '+%Y-%m-%dT%H:%M:%S'
[ls][-l]
Child pid=54602 executing command ls...
total 32
-rwxr-xr-x  1 jonathanleffler  staff  9076 Dec  3 21:18 vp13
-rw-r--r--  1 jonathanleffler  staff  1148 Dec  3 21:18 vp13.c
drwxr-xr-x  3 jonathanleffler  staff    96 Dec  3 21:15 vp13.dSYM
Child 54602 exited with status 0x0000
[pwd]
Child pid=54603 executing command pwd...
/Users/jonathanleffler/soq/so-6513-7710
Child 54603 exited with status 0x0000
[ls][-C][-F]
Child pid=54604 executing command ls...
vp13*      vp13.c     vp13.dSYM/
Child 54604 exited with status 0x0000
[date][+%Y-%m-%dT%H:%M:%S]
Child pid=54605 executing command date...
2020-12-03T21:23:55
Child 54605 exited with status 0x0000
$

I trust that isn't too flexible for you.

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