[ACCEPTED]-Is there a subshell created when I run `sh -c "command"`, a new shell or none of these?-command-line

Accepted answer
Score: 11

I think that with examples it's possible 42 to understand the situation
(in my case 41 sh is a symbolic link to /bin/dash).
I did this tests 40 for sh:

echo $$ ; sh -c 'echo $$ ; sh -c '"'"'echo $$'"'"' '
16102
7569
7570

Three different PID, three different shell. (If 39 there are different shells, there is not a subshell spawn).


In 38 a similar way for BASH

echo $$ $BASHPID, $BASH_SUBSHELL ; bash -c 'echo $$  $BASHPID $BASH_SUBSHELL  ; bash -c '"'"'echo  $$ $BASHPID $BASH_SUBSHELL '"'"' '
16102 16102, 0
10337 10337 0
10338 10338 0

Three different $BASHPID no different 37 $BASH_SUBSHELL (see note below for differences between 36 $$ and $BASHPID).
If we were in a subshell that do not require 35 to be reinitialized, then $$ and $BASHPID should be 34 different.
In the same way $BASH_SUBSHELL is not incremented, it 33 is always 0. So 2 clues to say again that 32 no new subshell are spawned, we have only new shells.


From 31 man bash (4.2.45(1)-release) I report some pertinent 30 parts about when a subshell is spawned:

  1. Each command in a pipeline is executed 29 as a separate process (i.e., in a subshell).

  2. If 28 a command is terminated by the control operator 27 &, the shell executes the command in the background in a subshell. The shell 26 does not wait for the command to finish, and 25 the return status is 0.

    Commands separated 24 by a ; are executed sequentially; the shell 23 waits for each command to terminate in turn. The 22 return status is the exit status of the 21 last command executed. ...

  3. ( list 20 ) list is executed in a subshell environment
    { list; } list 19 is simply executed in the current shell 18 environment.

  4. A coprocess is a shell command preceded 17 by the coproc reserved word. A coprocess is executed 16 asynchronously in a subshell...

  5. $ Expands to the process 15 ID of the shell. In a () subshell, it expands to the 14 process ID of the current shell, not the subshell.

Notes:

  • BASHPID Expands to the process ID of the current bash process. This differs from $$ under certain circumstances, such as subshells that do not require bash to be re-initialized.
  • BASH_SUBSHELL Incremented 13 by one each time a subshell or subshell 12 environment is spawned. The initial value 11 is 0.

  • For the differences between the use 10 of single quote '' an double quote "" you can see this question. Let 9 we remember only that if you write the commands 8 within double quote"" the variables will be 7 evaluated via parameter expansion from the 6 original shell, if extquote is enabled as it is by default 5 from shopt.(cfr. 4.3.2 The shopt builtin in the Bash Reference Manual)

    *extquote* If set, $'string' and $"string" quoting 4 is performed within ${parameter} expansions 3 enclosed in double quotes. This option is 2 enabled by default.

For further references 1 you may find useful e.g.

Score: 8

I would say not.

A subshell is typically 20 reserved for any instance where the shell 19 process needs to perform an operation in 18 an isolated environment, but with access 17 to (a copy of) the current state of the 16 shell, including all global and local variables.

Examples:

  • Pipelines: echo x | read y
  • Command substitution: line=$( read < file && echo "$REPLY" )

In 15 most cases, this would result in the shell 14 process forking itself.

In recent updates 13 of ksh93, some subshells may not actually 12 fork a new process.

The crux of the matter 11 is that a subshell is always created implicitly.

Running 10 sh -c ... will create a new shell process, which will 9 discard most of the state and start from 8 scratch. That means that normal (local, global) shell 7 variables are gone. Naturally, the new 6 shell will have a copy of all exported variables.


A 5 different interpretation of the question 4 could be Does the -c option fork a new process for running ...? Answer: No. It doesn't. However, certain 3 commands passed into the -c argument may require 2 the shell to spawn a subshell, just as when 1 they'd be part of a script, or typed interactively.

Score: 7

I made a check of it as well and no, I don't 40 think it (-c) summons a subshell. If we refer 39 to sh itself, the yes sh is a shell that gets 38 summoned, but not if it's about a subshell 37 within sh itself. We can verify this by running 36 a command like:

# bash -c 'pstree -p; echo Value of PPID in Callee: $PPID; echo Callee PID: $BASHPID / $$'; echo "Caller PID: $$"
bash(28860)───bash(17091)───pstree(17092)
Value of PPID in Callee: 28860
Callee PID: 17091 / 17091
Caller PID: 28860

As you can see the called 35 shell (17091) and the caller shell (28860) are 34 both connected directly as child-parent. There's 33 nothing in between them. $BASHPID and $$ are even 32 the same, in which case should be different 31 if you're on a subshell. This just tells 30 that there's no subshell summoned when calling 29 commands with -c.

There's only one special 28 behavior to this, and that is when summoning 27 a single external binary e.g.:

# bash -c 'pstree -p'; echo "Caller PID: $$"
bash(28860)───pstree(17124)
Caller PID: 28860

There bash 26 saves itself from forking and decided to 25 just directly exec() the only command. You 24 might think that perhaps bash always does 23 that to the last command if the command 22 refers to an external executable binary, but 21 no it doesn't:

# bash -c 'echo Value of PPID in Callee: $PPID; echo Callee PID: $BASHPID / $$; pstree -p'; echo "Caller PID: $$"
Value of PPID in Callee: 28860
Callee PID: 17128 / 17128
bash(28860)───bash(17128)───pstree(17129)
Caller PID: 28860

Now about

echo $BASHPID, $BASH_SUBSHELL

and

sh 20 -c "echo $BASHPID, $BASH_SUBSHELL"

and the 19 results are the same.

It should be the same 18 if echo $BASHPID, $BASH_SUBSHELL is executed in the same shell since 17 "echo $BASHPID, $BASH_SUBSHELL" is first expanded by the shell that interprets 16 the command before it's passed as an argument 15 to sh. If BASHPID is let's say 28860 and BASH_SUBSHELL 0, then the 14 expanded value of "echo $BASHPID, $BASH_SUBSHELL" is 'echo 28860, 0' in which case the 13 command would actually be sh -c 'echo 28860, 0'. The proper way 12 to this actually is to use a single quote 11 to allow interpretation only within the 10 context of the new called shell: sh -c 'echo $BASHPID, $BASH_SUBSHELL', although 9 I'm not really sure if the command itself 8 would be helpful for testing.

So basically 7 what I'm saying is that the test echo $BASHPID, $BASH_SUBSHELL + sh -c "echo $BASHPID, $BASH_SUBSHELL" doesn't 6 prove anything if -c summons a subshell or 5 not and that the guy who told you that it 4 could mislead since the variables may be 3 substituted is correct.

Nevertheless, my 2 own test showed that Bash really doesn't 1 summon a subshell with it (-c).

Score: 4

Check this:

$ name=foo
$ echo $name
foo
$ sh -c "echo $name"
foo
$ sh -c 'echo $name'

$ 

You need ' in stead of " in your 3 command. Else $name will get evaluated to foo before 2 execution

And to answer your question, yes, it 1 does create/spawn a new shell.

Score: 3

sh will spawn a subshell. But the subshell 5 id stays the same

21934 pts/0    Ss     0:00 -bash
21963 pts/0    S      0:00  \_ /usr/bin/sudo -u root -H /bin/bash -c  export AUDITUSER=ch002854; cd $HOME && exec -a '-bash' /bin/bash
22031 pts/0    S      0:00      \_ -bash
 2969 pts/0    S      0:00          \_ sleep 1000
 2993 pts/0    S      0:00          \_ sleep 1000
 3726 pts/0    R+     0:00          \_ ps af

With sh -c it will just 4 run the command. This will reinitialize 3 your environment variables and therefore 2 it resets $BASH_SUBSHELL to its default 1 0.

# sh -c 'echo $BASHPID, $BASH_SUBSHELL'
12671, 0

While with `` or () you can create a subshell

# (echo $BASHPID, $BASH_SUBSHELL)
13214, 1
Score: 2

Regardless

Running this simple line will show you a 13 lot:

$ echo $$;sh -c 'echo $$;ps axfw | grep -B2 $$'
14152
12352
14147 ?        S      0:00 xterm
14152 pts/4    Ss     0:00  \_ bash
12352 pts/4    S+     0:00      \_ sh -c echo $$;ps axfw | grep -B2 $$
12353 pts/4    R+     0:00          \_ ps axfw
12354 pts/4    S+     0:00          \_ grep -B2 12352

This is clearly a child but what's a subshell?

Well, my 12 current running shell pid is 14152

$ echo $$ $BASHPID $BASH_SUBSHELL 
14152 14152 0
$ (echo $$ $BASHPID $BASH_SUBSHELL)
14152 12356 1
$ ( (echo $$ $BASHPID $BASH_SUBSHELL) )
14152 12357 2

Well nice: BASHPID is 11 a dynamic variable which take alway the value of 10 executing pid:

$ echo $BASHPID | sed \$a$BASHPID | sed \$a$BASHPID
12371
12372
12373

Hmmm where is my current working 9 pid?

$ sed "\$a$BASHPID $$" < <(echo "$BASHPID $$"| sed "\$a$BASHPID $$")
12386 14152
12387 14152
14152 14152

Well I've find them!

$ echo $BASHPID $$;(echo $BASHPID $$;ps axfw | grep -B3 $BASHPID)
14152 14152
12469 14152
14152 pts/4    Ss     0:00  \_ bash
12469 pts/4    S+     0:00      \_ bash
12470 pts/4    R+     0:00          \_ ps axfw
12471 pts/4    S+     0:00          \_ grep -B3 12471

Conclusion

When you

$ echo $BASHPID $$ $BASH_SUBSHELL;(echo $BASHPID $$ $BASH_SUBSHELL)
14152 14152 0
12509 14152 1

use parenthesis 8 or pipe (|), you will create subshell which is a forked 7 child of a running shell.

But when you

$ echo $BASHPID $$ $BASH_SUBSHELL;bash -c 'echo $BASHPID $$ $BASH_SUBSHELL'
14152 14152 0
12513 12513 0

You 6 will burn a child, running a shell interpreter, so 5 it's a subshell, but not linked to his parent.

Nota: If 4 the child is not linked to his parent, they 3 use same I/O files descriptors. So if you 2 close your window (pts/4 in my run), you will 1 send a SIGHUP to all process using them.

Score: 1

In this answer I'm thinking of subshell 24 the same way as I think of a subprocess.

First 23 off, don't be confused by variable expansion. If 22 you write a variable in double quotes, it 21 will be expanded by the calling shell, not 20 the sh or its -c command. So

sh -c "echo $$" 

gives you the 19 PID of the invoking shell, because it expands 18 $$ before it invokes sh, whereas

sh -c 'echo $$' 

gives you 17 the PID of the sh command that has been 16 invoked, because the single quotes tell 15 the invoking shell to pass the string $$ to 14 sh unchanged.

That said, the general answer 13 to your question is:

  1. The sh command is definitely a subshell, invoked by the parent shell when it sees 'sh'
  2. When you note that the argument to -c is treated by it as a shell script, then you see that you'll get a grand-subshell of the invoked sh, whenever a regular shell script would get one.

More on item 2: Some 12 shell builtins create subshells; others 11 do not. The sh man page talks about this; check 10 out the "if" builtin, or constucts that 9 use backquotes ``. Usage of pipes also 8 causes subshells. You can also deliberately 7 force a subshell by enclosing commands in 6 parentheses. However, enclosing commands 5 in braces {} does NOT of itself cause a 4 subshell.

sh is designed to run commands, so 3 in most cases you will have subshells. Notable 2 exceptions are the 'case' builtin, variable 1 assignment, option setting, and the . command.

More Related questions