3

I have a ./scr script.

abc@~ $ cat scr
#!/bin/bash
ps
echo '-------'
echo "$(ps)"

abc@~ $ 

My goal is to find out how are the subprocesses created. As far as I know, the $(...) part should create a subshell, and therefore a new process. So the number of processes in the second call of ps should be larger.

That's exactly how it is if I source the script in the current shell:

abc@~ $ . scr
  PID TTY           TIME CMD
 1659 ttys000    0:00.17 -bash
-------
  PID TTY           TIME CMD
 1659 ttys000    0:00.17 -bash
 1785 ttys000    0:00.00 -bash
abc@~ $ 

However, when launching in an interpreting shell, the number of processes doesn't differ:

abc@~ $ ./scr
  PID TTY           TIME CMD
 1659 ttys000    0:00.17 -bash
 1790 ttys000    0:00.00 /bin/bash ./scr
-------
  PID TTY           TIME CMD
 1659 ttys000    0:00.17 -bash
 1790 ttys000    0:00.00 /bin/bash ./scr
abc@~ $ 

Why is it so?

Similarly, why does ps give the same output as (ps)?

abc@~ $ ps
  PID TTY           TIME CMD
 1659 ttys000    0:00.18 -bash
abc@~ $ (ps)
  PID TTY           TIME CMD
 1659 ttys000    0:00.18 -bash
abc@~ $ 

An interesting thing is that prepending the ps command with any other command forces it to "produce" the expected new process (produces the expected process in the script at the top, in ./scr, as well).

abc@~ $ (echo 1; ps)
1
  PID TTY           TIME CMD
 1659 ttys000    0:00.20 -bash
 1823 ttys000    0:00.00 -bash
abc@~ $ 

Is (ps) being somehow "optimised" by the shell? And why is it not, when sourced?

A side note: the system is actually a macOS, I don't expect it to behave differently in that case, though.


EDIT:

As in this answer, the subshell seems to be a subject to optimisation, and therefore is not being run in a separate, newly initiated shell, because apparently it's not needed.

Why is it needed when running in current shell, then (. scr)?

2

1 Answer 1

4

Command substitution happens in "subshell environment", not necessarily a full-blown subshell; the shell will avoid creating a useless process if the effect of having a subshell environment can be achieved without it. If you want to see a full-blown subshell, give it something to do which needs a full blown subshell; compare:

$ echo "$(ps fax)"
  PID TTY      STAT   TIME COMMAND
  ...
 1317 ?        Ss     0:00 /usr/sbin/sshd -D
 1751 ?        Ss     0:00  \_ sshd: alexp [priv]
 1788 ?        S      0:00      \_ sshd: alexp@pts/0
 1789 pts/0    Ss+    0:00          \_ -bash
 1822 pts/0    R+     0:00              \_ ps fax
  ...
$ echo "$(ps fax; echo)"
  PID TTY      STAT   TIME COMMAND
  ...
 1317 ?        Ss     0:00 /usr/sbin/sshd -D
 1751 ?        Ss     0:00  \_ sshd: alexp [priv]
 1788 ?        S      0:00      \_ sshd: alexp@pts/0
 1789 pts/0    Ss+    0:00          \_ -bash
 1823 pts/0    S+     0:00              \_ -bash
 1824 pts/0    R+     0:00                  \_ ps fax
  ...
3
  • 1
    So as I suspected, it's kind of optimised. Isn't such a little unpredictable behaviour unusual for unix, though? Also, the question why sourcing the file creates such process remains unanswered.
    – Dart Dega
    Commented Jan 26, 2017 at 9:42
  • Just to say that the ksh93 shell does not fork off a new shell instance in the second example. In fact, I'm finding it surprisingly difficult to get it to do that without running it as a background process.
    – Kusalananda
    Commented Jan 26, 2017 at 14:17
  • 1
    @DartDega this answer is incorrect; bash does fork and creates a new process everytime it runs a subshell like (...) or $(...); without exception. The optimization is that bash will turn a simple command like ps into exec ps (when it's the last command in a subshell, and there are no other complications, like trap handlers) changing a fork + exec + wait into a single exec. Since bash will (obviously) also fork each time it runs an external command like ps; ..., this means that (ps); ... -> (exec ps); ... is indistinguishable from ps; ....
    – user313992
    Commented Nov 12, 2021 at 1:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .