Chenglu
Chenglu

Reputation: 1997

Why shell would start another shell process in this situation?

Here's the code

#!/bin/bash
echo $$
cd $HOME && sleep 10 &
exit 0

now lets run sh test.sh

I got the result: 21936 which is the pid of the shell process I have ran.

and if I do ps -ef | grep test.sh within 10 seconds which is the sleep time.

I got root 21937 1 0 12:41 pts/0 00:00:00 sh test.sh

Q1: It's supposed to be no test.sh but just a sleep process. Why there's still a test.sh ?

Q2: It seems like the test.sh I grep out is not the same as the test.sh I ran in the terminal, depend on the PID. So how did the new test.sh come out?


Hi, there's another case of this, if I change

cd $HOME && sleep 10 &

to

cd $HOME; sleep 10 &

It will not act the same way, the test.sh will disappear right after executing sh test.sh, there's only one sleep process.

Upvotes: 1

Views: 68

Answers (2)

Christian.K
Christian.K

Reputation: 49220

(OK, I'll go out on a limb and turn my guess/comment into an answer.)

Since the &&-operator is essentially a shell-builtin, i.e. it needs to be processed by the shell, using it together with & will create a child process for the/a shell and not the individual parts of it (or just the last part of it as it looks, you'd expected).

That even happens when all commands chained with && are external commands. For example, sleep 3 && sleep 5 & will also create a sub shell process.

The ; just separates individual commands, as if they'd been written on separate lines. So in this case only the command that preceeds the & is forked ("send to the background").

(Of course, the original process that gets forked is always the shell - that is just the way how fork works - but in the second case, it is replaced with the executable of the actual command, sleep in your example).

Upvotes: 2

4ae1e1
4ae1e1

Reputation: 7614

From Bash Reference Manual:

If a command is terminated by the control operator &, the shell executes the command asynchronously in a subshell.

That is to say, the parent shell process is forked (in spawning the subshell).

You can easily test this with the following snippet:

#!/usr/bin/env bash
print_subshell_level () { echo $BASH_SUBSHELL; }

printf "foreground: "
print_subshell_level

printf "background: "
print_subshell_level &

Output:

foreground: 0
background: 1

Upvotes: 1

Related Questions