脚本

时间:2017-12-18 15:59:54

标签: shell kill raise

我有一个非常庞大的存档,必须逐个文件提取并进一步处理。我没有足够的内存来提取整个存档(无论是在RAM中还是在闪存中) - 因此我写了一个小应用程序,它在每个提取的文件后停止(raise(SIGSTOP))。等效的可能就是这段代码:

#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;
}

当我在终端中执行此操作时,这工作正常:

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

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

但是从脚本调用方法时,命令永远不会返回:

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

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

为什么终端和脚本的行为如此不同?有没有办法改变这种行为?

谢谢,卡尔

1 个答案:

答案 0 :(得分:1)

非交互式shell中的作业控制是非默认的,但您可以显式启用它:

set -m

因此,如果我们修改您的脚本,以便在shebang上添加set -m行或-m,如下所示:

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

...然后在BACK之后发出stopping

引自bash手册页section on set,重点补充:

  

-m监控模式。作业控制已启用。 默认情况下,对于支持它的系统上的交互式shell,此选项处于启用状态(请参阅上面的JOB CONTROL)。所有进程都在一个单独的进程组中运行。后台作业完成后,shell会打印一行包含退出状态的行。