Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does (ps -f) create no subshell but a separate process?

Tags:

linux

shell

unix

I need some help because I don't get something. From what I read from Internet, a subshell is created when we execute a shell script or if we run command in brackets: ( )

I tried to test this with a script which contains only the following command:

ps -f

When I run it I see the following result:

ID      PID  PPID  C STIME TTY          TIME CMD 
me     2213  2160  0 08:53 pts/14   00:00:00 bash 
me     3832  2213  0 18:41 pts/14   00:00:00 bash 
me     3833  3832  0 18:41 pts/14   00:00:00 ps -f

Which is good, because I see that my bash process has spawned another bash process for my script.

But when I do:

( ps -f )

it produces:

UID     PID  PPID  C STIME TTY          TIME CMD 
me     2213  2160  0 08:53 pts/14   00:00:00 bash 
me     3840  2213  0 18:46 pts/14   00:00:00 ps -f

So if brackets spawn a subshell why it is not shown in the processes? And why does ps -f is counted as another process? Does every command run as a separate process?

like image 899
CuriousGuy Avatar asked Mar 19 '23 13:03

CuriousGuy


2 Answers

It seems you've caught bash in a little bit of an optimization. if a subshell contains only a single command, why really make it a subshell?

$ ( ps -f )
UID        PID  PPID  C STIME TTY          TIME CMD
jovalko  29393 24133  0 12:05 pts/10   00:00:00 bash
jovalko  29555 29393  0 12:07 pts/10   00:00:00 ps -f

However, add a second command, say : (the bash null command, which does nothing) and this is the result:

$ ( ps -f ; : )
UID        PID  PPID  C STIME TTY          TIME CMD
jovalko  29393 24133  0 12:05 pts/10   00:00:00 bash
jovalko  29565 29393  0 12:08 pts/10   00:00:00 bash
jovalko  29566 29565  0 12:08 pts/10   00:00:00 ps -f

One of the main reasons to use a subshell is that you can perform operations like I/O redirection on a group of commands instead a single command, but if your subshell contains only a single command there's not much reason to really fork a new bash process first.

As to ps counting as a process, it varies. Many commands you use like ls, grep, awk are all external programs. But, there are builtins like cd, kill, too.

You can determine which a command is in bash using the type command:

$ type ps
ps is hashed (/bin/ps)
$ type cd
cd is a shell builtin
like image 61
FatalError Avatar answered Mar 23 '23 04:03

FatalError


The main part of the question is:

Does every command run as a separate process?

YES!. Every command what isn't built-in into bash (like declare and such), runs as separate process. How it is works?

When you type ps and press enter, the bash analyze what you typed, do usual things as globbing, variable expansionas and such, and finally when it is an external command

  • the bash forks itself.

The forking mean, than immediatelly after the fork, you will have two identical bash processes (each one with different process ID (PID)) - called as "parent" and "child", and the only difference between those two running bash programs is, than the "parent" gets (return value from the fork) the PID of the child but the child don't know the PID of the parent. (fork for the child returns 0).

  • after the fork, (bash is written this way) - the child replaces itself with the new program image (such: ps) - using the exec call.
  • after this, the child bash of course doesn't exist anymore, and running only the newly executed command - e.g. the ps.

Of course, when the bash going to fork itself, do many other things, like I/O redirections, opens-closes filehandles, changes signal handling for the child and many-many other things.

like image 25
jm666 Avatar answered Mar 23 '23 03:03

jm666