4

The question is the title. I couldn't figure out why the terminal will shut down immediately after 'ls' is executed. A Linux shell is like this:

1.while (1) {
2. char *cmd = read_command();
3. int child_pid = fork();
4. if (child_pid == 0) {
5. exec(cmd);
6. }else {
7. waitpid(child_pid);
8. }
9.}

So, if we run 'exec ls' in shell, cmd is a string of 'exec ls'. A child process is forked in line 3. In line 5, exec(cmd) will replace the child process but won't affect the father process. If the father process is not affected, why the terminal shuts down then?

Please show me the flaws in my reasoning above.

zcb
  • 131
  • 1
  • 2
  • 10

3 Answers3

6

If you run ls, your shell process will start up another process to run the ls program, then it will wait for it to finish. When it finishes, control is returned to the shell.

With exec ls, you actually replace your shell program in the current process with the ls program so that, when it finishes, there's no shell waiting for it.

Most likely, you will have either a terminal program or init as the parent which is what will take over when your process exits. That's why your shell disappears, because you explicitly told it to.

See this answer for an explanation of the shell/ls (non-exec) situation.


As for your update, the shell does not always create a separate process to do stuff. There are a large number of internal commands (such as cd or alias) that do not involve making other processes (this depends on your shell, of course but, as one example, you can see the bash internal commands by entering man bash-builtins at a command prompt).

exec is one of these. It simply replaces the shell itself (ie, not a forked child process) with the program you specify. That's why it doesn't act as you think.

Community
  • 1
  • 1
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Thanks! I updated the question just now which described my confusions more clearly. Would you please read it again? – zcb Jan 28 '13 at 03:35
  • @zcb, see the updated answer. Shells don't always run a child process for each command. Things like `exec`, `cd`, `alias` and so on affect the _current_ shell. `exec` is an explicit request to the shell (in _current_ process) to replace itself. See `man bash-builtins` for some examples. – paxdiablo Jan 28 '13 at 03:47
3

Exec overrides the current process with another one. Normally when you call "ls" a new process is created that runs as child of your shell. "exec ls" overrides your current shell with the "ls" process. Thus as soon as "ls" terminates your terminal closes.

bikeshedder
  • 7,337
  • 1
  • 23
  • 29
  • Do you mean the shell treats the command 'exec *' specially? Do you mean: the shell won't fork a child process for 'exec *' while overrides itself? If this is true, why the shell treats such kind of commands in a different way? – zcb Jan 28 '13 at 03:53
  • Indeed. exec is a built in shell command which does not fork a new process but overrides itself. – bikeshedder Jan 28 '13 at 11:47
2

exec overwrites the running process with a new process image. So, in your current process, the shell you're running is overwritten by the ls executable image, and once ls exits, the process is shut down.

radical7
  • 8,957
  • 3
  • 24
  • 33