Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What happens when I use `&` with a function in a Bash script?

Tags:

linux

bash

shell

I'm debugging an oddity with a shell script and wondering whether I've misunderstood how Bash's "fork" (&) works, perhaps because I usually use it in single commands through a terminal, e.g.:

[~me]$ someExecutable &

Now, in a shell script:

foo() {
   echo "logic"
}

bar() {
   echo "idic"
}

baz() {
   echo "katra"
}

foo &
bar
baz

My intention is for the function foo to be invoked asynchronously, and then for the remainder of the script to continue executing in the original process context.

When I execute this example script I do get the expected output:

logic
idic
katra

(that is, only single apparent calls to bar and baz; I'm not at all bothered by the relative order of the three lines of output, which I understand may vary)

but I may be misunderstanding both the output and the script itself. If so, that would certainly explain the oddity I'm seeing in my real code, and save me from having to dig any further.

Is it possible that, in the child process, after the call to foo, the forked shell script will continue? Meaning that the remainder of my shell script will be executed twice?

What really happens when I use & like this in a Bash script?

like image 484
Lightness Races in Orbit Avatar asked Jan 13 '14 12:01

Lightness Races in Orbit


2 Answers

The ampersand is only forking the call to foo() in your example. It is not forking the entire script. Only foo() runs in a separate thread, which exits when foo() finishes. bar() and baz() continue to run in the same thread

like image 69
bjornruffians Avatar answered Nov 14 '22 22:11

bjornruffians


The & in bash is not a fork. It tells bash to launch the command in a subshell, and continue parsing for other commands (instead of waiting for that command to finish).

Therefore, as you expected, it runs 'foo' in the background, and continues to process the 'bar' and 'baz' command in the top level shell. No forking of the calling shell occurred, but 'foo' was run in the background.

So the output of "foo" could actually happen after bar or baz, depending on its content.. but as it uses "echo", which is a shell builtin, by the time the "foo" background process is setup, the "echo" is immediately available to it : therefore chances are good you see its output before the calling shell passes to the next command, which apparently is what happens in your case. (But YMMV! If "foo" was calling a heavy external command, it's likely its output would occur later on)

In the terminal, it's almost the same thing: you could consider a terminal window with a shell prompt as a file script for that shell, that the login shell is reading "as you type it". The behavior is almost the same.

like image 31
Olivier Dulac Avatar answered Nov 14 '22 21:11

Olivier Dulac