Charly
Charly

Reputation: 1352

SIGSTOP does not work when scripted

I have a really huge archive, which must be extracted file by file and further processed. I don't have enough memory to extract the whole archive (neither in RAM nor on the flash) - thus I wrote a small application which stops (raise(SIGSTOP)) after each extracted file. An equivalent could be this code:

#include <stdio.h>
#include <signal.h>

int main() {
    printf("started.\n"); fflush(stdout);
    sleep(2);                             // extracting archive
    printf("stopping\n"); fflush(stdout);
    raise(SIGSTOP);                       // stopping
    printf("resume + done\n"); fflush(stdout);
    return 0;
}

This works fine while I execute this in the terminal:

$ gcc -o dosleep main.c
$ ./dosleep 
started.
stopping

[1]+  Stopped                 ./dosleep
$ fg
./dosleep
resume + done
$ 

But when calling the method from a script, the command never returns:

$ cat doit.sh 
#!/bin/sh
echo "STARTING"
./dosleep
echo "BACK"
$ ./doit.sh 
STARTING
started.
stopping

^C^C^C^C^C^C

Why do terminal and script behave so differently? Is there a way to change this behavior?

Thanks, Karl

Upvotes: 1

Views: 293

Answers (1)

Charles Duffy
Charles Duffy

Reputation: 295629

Job control is off-by-default in noninteractive shells, but you can enable it explicitly:

set -m

Thus, if we modify your script to add either the set -m line or a -m on the shebang as follows:

#!/bin/bash -m
./start-delay
echo BACK

...then BACK is emitted after stopping.


Quoting from the bash man page section on set, emphasis added:

-m Monitor mode. Job control is enabled. This option is on by default for interactive shells on systems that support it (see JOB CONTROL above). All processes run in a separate process group. When a background job completes, the shell prints a line containing its exit status.

Upvotes: 2

Related Questions