Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple exec in a shell script

Tags:

bash

shell

sh

exec

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?

like image 315
Alex Rothberg Avatar asked Nov 14 '25 21:11

Alex Rothberg


1 Answers

The use of & implie a sub-process.

Background Commands – &
  If a command is terminated by the control operator ampersand (&), the
  shell executes the command asynchronously – that is, the shell does not
  wait for the command to finish before executing the next command.

But exec is used to replace current process by command:

 exec [command arg ...]
        Unless command is omitted, the shell process is replaced with the
        specified program (which must be a real program, not a shell
        builtin or function).  Any redirections on the exec command are
       marked as permanent

So this features are mutually exclusive! In syntaxe:

exec bash -c 'sleep 12' &

here exec has 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 shell.

Another demo:

ps --tty $(tty) fw
    PID TTY      STAT   TIME COMMAND
  82905 pts/9    Ss     0:00 /bin/bash
  83360 pts/9    R+     0:00  \_ ps --tty /dev/pts/9 fw

yes >/dev/null &
[1] 83860
exec yes >/dev/null &
[2] 84150

ps --tty $(tty) fw
    PID TTY      STAT   TIME COMMAND
  82905 pts/9    Ss     0:00 /bin/bash 
  83860 pts/9    R      0:32  \_ yes
  84150 pts/9    R      0:11  \_ yes
  84181 pts/9    R+     0:00  \_ ps --tty /dev/pts/9 fw

There is no difference between process 83860 and 84150 (expect pid number and start time, asked for)!

ps --tty $(tty) ho pid,cmd | sed 's/y[e]s//p;d' |
    xargs --no-run-if-empty --verbose kill
kill 83860 84150
[1]-  Terminated              yes > /dev/null
[2]+  Terminated              exec yes > /dev/null
like image 147
F. Hauri Avatar answered Nov 17 '25 10:11

F. Hauri



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!