3

What happens if you have multiple exec commands in a shell script, for example:

#!/bin/sh

exec yes > /dev/null &
exec yes alex > /dev/null

I assume that a fork is still needed in order to execute the first command since the shell needs to continue executing?

Or does the & specify to create a sub process in which the exec is actually then run?

Alex Rothberg
  • 10,243
  • 13
  • 60
  • 120

2 Answers2

3

The use of & implie a sub-process.

So exec have no effect.

Demo:

export LANG=C
echo $$
17259
exec sh -c 'echo $$;read foo' &
[1] 17538
17538

[1]+  Stopped                 exec sh -c 'echo $$;read foo'   
fg

exec sh -c 'echo $$;read foo'  
17259

I run the script: echo $$;read foo in order to prevent exit before having quietly read previous output.

In this sample, the current process ID is 17259.

When run with ampersand (&), the output is another pid (bigger). when run without ampersand, the new shell replace the command and is not forked.

Replacing the command by:

sh -c 'echo $$;set >/tmp/fork_test-$$.env;read'

re-running the whole test will generate two files in /tmp.

On my desk, I could read:

19772
19994
19772

So I found two files in /tmp:

-rw-r--r-- 1 user0 user0 2677 jan 22 00:26 /tmp/fork_test-19772.env
-rw-r--r-- 1 user0 user0 2689 jan 22 00:27 /tmp/fork_test-19994.env

If I run: diff /tmp/fork_test-19*env, I read:

29c29
< SHLVL='0'
---
> SHLVL='1'
46a47
> _='/bin/sh'

So the first run, with ampersand is in a sublevel.

Nota: This was tested under many different .

F. Hauri - Give Up GitHub
  • 64,122
  • 17
  • 116
  • 137
  • It has no effect in the forking shell; it has a very big effect in the *forked* shell. – chepner Jan 21 '17 at 23:24
  • 2
    The first one; it replaces the forked shell running in the background with `yes` rather than having *that* shell fork in order to run `yes`, wait for it to complete, then exit itself. – chepner Jan 21 '17 at 23:27
  • @chepner I'm not sure I understand your mean... It's a fork!? Could you explain or address some references? – F. Hauri - Give Up GitHub Jan 21 '17 at 23:47
  • Forking is how *any* new process gets started (at least under Unix). For a background job, the shell forks, and the command list terminated by `&` is processed by the background shell. – chepner Jan 22 '17 at 03:19
  • 2
    @chepner A shell is a background shell, depending on how it is run. Anyway having `exec` or not at begining of a line terminated by an ampersand don't have effect! (If I'm wrong, I would appreciate to learn more!) – F. Hauri - Give Up GitHub Jan 22 '17 at 09:11
-1

The shell forks to run the background process, but that means the new shell still needs to fork to run yes. Using exec eliminates the fork in the subshell.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • Your explanation seemed logical to me, but I tried launching both commands and comparing the resulting process tree with "ps f", and I get the same tree for both (and in both case there does not seem to be an extra "bash" between the interactive shell and "yes"). I tried one more thing : adding "wait" at the end of each command. In this case, I was surprise to see that it is the case with "exec" that has an extra process (I see two sibling processes for "yes"). Is that consistent with your answer? – Fred Jan 22 '17 at 02:20
  • `bash` may be optimized to automatically `exec` in a subshell/subprocess that only needs to run one command. I'm not sure about the case with `wait`. – chepner Jan 22 '17 at 03:18
  • 1
    I'm sorry, but until you post references explaining your mean, I just think this is totally wrong: Even using [tag:dash] or [tag:busybox] my experiment tend to tell: *there is no difference by using `exec` or not, while using ampersand.* – F. Hauri - Give Up GitHub Jan 22 '17 at 21:27
  • 1
    What mean *background*? Ampersand **implie** *background* job! Care: `exec` is not same than `nohup`! http://stackoverflow.com/q/15595374/1765658 – F. Hauri - Give Up GitHub Jan 22 '17 at 21:35