30

I have a script that I would like to fork at one point so two copies of the same script are running.

For example, I would like the following bash script to exist:

echo $$
do_fork()
echo $$

If this bash script truly existed, the expected output would be:

<ProcessA PID>
<ProcessB PID>
<ProcessA PID>

or

<ProcessA PID>
<ProcessA PID>
<ProcessB PID>

Is there something that I can put in place of "do_fork()" to get this kind of output, or to cause the bash script to do a C-like fork?

3 Answers 3

28

Yes. Forking is spelled &:

echo child & echo parent

What may be confusing you is that $$ is not the PID of the shell process, it's the PID of the original shell process. The point of making it this way is that $$ is a unique identifier for a particular instance of the shell script: it doesn't change during the script's execution, and it's different from $$ in any other concurrently running script. One way to get the shell process's actual PID is sh -c 'echo $PPID'.

The control flow in the shell isn't the same as C. If in C you'd write

first(); fork(); second(); third();

then a shell equivalent is

after_fork () { second; third; }
first; after_fork & after_fork

The simple shell form first; child & parent corresponds to the usual C idiom

first(); if (fork()) parent(); else child();

& and $$ exist and behave this way in every Bourne-style shell and in (t)csh. $PPID didn't exist in the orignal Bourne shell but is in POSIX (so it's in ash, bash, ksh, zsh, …).

10
  • 4
    But that's basically "fork + exec", not just fork.
    – mattdm
    Feb 18, 2011 at 0:41
  • @mattdm: Uh? & is fork, there's no exec involved. Fork+exec is when you launch an external command. Feb 18, 2011 at 0:47
  • 2
    @Gilles: The bash control operator & starts a subshell in which the given command is executed. Fork + exec. You can't just put & with no preceding command to execute.
    – mattdm
    Feb 18, 2011 at 0:58
  • 2
    @Gilles — that's an implementation detail because echo is a builtin. Try it with /bin/echo and of course there is an exec. But I don't mean literally; I mean conceptually. You can't fork and continue from there without giving some command — it just doesn't work like that.
    – mattdm
    Feb 18, 2011 at 1:30
  • 8
    Well, if "Forking is spelled &" were a true statement, you could put & on a line by itself. But you can't. It doesn't mean "fork here". It means "execute the preceding command in the background in a subshell".
    – mattdm
    Feb 18, 2011 at 1:36
13

Yes, it's called subshells. Shell code inside parenthesis is run as a subshell (fork). However the first shell normally waits for the child to complete. You can make it asynchronous using the & terminator. See it in in action with something like this:

#!/bin/bash

(sleep 2; echo "subsh 1")&
echo "topsh"

$ bash subsh.sh

1
  • 5
    The parentheses create a subshell, but that's fork+wait. & is fork alone. If you want to execute more than one pipeline in the child process, it's enough to use braces (which perform grouping without creating a child process): { sleep 2; echo child; } & Feb 18, 2011 at 8:31
9

There's no native bash (or, to my knowledge, any other typical *nix shell) way of doing this. There's a lot of ways to spawn forked processes that do something else asynchronously, but I don't think there's anything that follows the exact semantics of the fork() system call.

The typical approach would be to have your top-level script spawn off helpers that do just the work you want split out. If you do $0 $@ & or whatever, you'll start at the beginning again and need to figure that out somehow.

I'm actually starting to think of several clever ways in which one might do just that....

But, before my brain gets too carried away with that, I think a pretty good rule is: if you're trying to write something in shell and it's getting full of clever tricks and you're wishing for more language features, it's time to switch to a programming language with those features.

4
  • 4
    Although your point is well taken- bash's syntax is arguably difficult and it's missing the more elegant data structures and features of Perl or Python, bash is as real as it gets- in its domain. It is a domain-specific language, and I would argue even better (more succinct, simpler) than eg Python in many instances. Can you administer a roomful of systems and not know Python? Yes. Can you do that and not know a lick of bash [programming]? I wouldn't want to try. After 30 years of shell programming I tell you it's as real as it gets. And yes, I speak Python. But don't confuse the youngsters.
    – Mike S
    May 10, 2016 at 13:21
  • 4
    That said, technically I like this answer more. To say that "&" is the answer to the user's question, "fork at one point so two copies of the same script are running" is to my mind confusing. What "&" does, according to the bash manual, is "...executes the [given] command in the background in a subshell." It must terminate a command, and it does involve a fork (technically, in Linux, a clone() ), but at that point two copies of the same script are not running.
    – Mike S
    May 10, 2016 at 13:39
  • The UNIX shell is (implements) a REAL programming language. Sep 14, 2022 at 5:37
  • @Luis Yeah, my 10-year-old tongue-in-cheek comment maybe isn't the best. I'll rephrase.
    – mattdm
    Sep 15, 2022 at 20:21

You must log in to answer this question.

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