using exec to execute a system command in a new process

50,221

Solution 1

You're missing a call to fork. All exec does is replace the current process image with that of the new program. Use fork to spawn a copy of your current process. Its return value will tell you whether it's the child or the original parent that's running. If it's the child, call exec.


Once you've made that change, it only appears that you need to press Enter for the programs to finish. What's actually happening is this: The parent process forks and executes the child process. Both processes run, and both processes print to stdout at the same time. Their output is garbled. The parent process has less to do than the child, so it terminates first. When it terminates, your shell, which was waiting for it, wakes and prints the usual prompt. Meanwhile, the child process is still running. It prints more file entries. Finally, it terminates. The shell isn't paying attention to the child process (its grandchild), so the shell has no reason to re-print the prompt. Look more carefully at the output you get, and you should be able to find your usual command prompt buried in the ls output above.

The cursor appears to be waiting for you to press a key. When you do, the shell prints a prompt, and all looks normal. But as far as the shell was concerned, all was already normal. You could have typed another command before. It would have looked a little strange, but the shell would have executed it normally because it only receives input from the keyboard, not from the child process printing additional characters to the screen.

If you use a program like top in a separate console window, you can watch and confirm that both programs have already finished running before you have to press Enter.

Solution 2

The Exec family of functions replaces the current process with the new executable.

To do what you need, use one of the fork() functions and have the child process exec the new image.

[response to update]

It is doing exactly what you told it: You don't have to press "enter" to finish the program: It has already exited. The shell has already given a prompt:

[wally@zenetfedora ~]$ ./z
before
22397
done
[wally@zenetfedora ~]$ 0               << here is the prompt (as well as the pid)
total 5102364
drwxr-xr-x.  2 wally wally       4096 2011-01-31 16:22 Templates
...

The output from ls takes awhile so it buries the prompt. If you want output to appear in a more logical order, add sleep(1) (or maybe longer) before the "done".

Solution 3

You're missing the part where execl() replaces your current program in memory with /bin/ls

I would suggest looking at popen() which will fork and exec a new process, then let you read or write to it via a pipe. (Or if you need read and write, fork() yourself, then exec())

Share:
50,221

Related videos on Youtube

CuriousMind
Author by

CuriousMind

Updated on July 09, 2022

Comments

  • CuriousMind
    CuriousMind almost 2 years

    I am trying to spawn a process that executes a system command, while my own program still proceeds and two processes will run in parallel. I am working on linux.

    I looked up online and sounds like I should use exec() family. But it doesn't work quite as what I expected. For example, in the following code, I only see "before" being printed, ,but not "done".

    I am curious if I am issing anything?

    #include <unistd.h>
    #include <iostream>
    
    using namespace std;
    
    main()
    {
       cout << "before" << endl;
       execl("/bin/ls", "/bin/ls", "-r", "-t", "-l", (char *) 0);
       cout << "done" << endl;
    }
    

    [UPDATE]

    Thank you for your guys comments. Now my program looks like this. Everything works fine except at the end, I have to press enter to finish the program. I am not sure why I have to press the last enter?

    #include <unistd.h>
    #include <iostream>
    
    using namespace std;
    
    main()
    {
       cout << "before" << endl;
       int pid = fork();
       cout << pid << endl;
       if (pid==0) {
          execl("/bin/ls", "ls", "-r", "-t", "-l", (char *) 0);
       }
       cout << "done" << endl;
    }
    
  • Hasturkun
    Hasturkun about 13 years
    Should add a wait for the child, rather than sleep really

Related