Shell脚本中的多任务

有时,在编写Shell脚本时,您想要在多个线程中执行一些操作。合适的情况可能是,例如,在多处理器主机上压缩大量大文件,并在单个连接速度受到限制的宽带宽上传输文件。



所有示例均以bash编写,但是(只需进行很少的更改)便可以在ksh中使用。Csh还具有管理后台进程的功能,因此也可以使用类似的方法。



作业控制



如果您喜欢阅读man,这是man bash中详细信息所在的部分的名称。我们使用以下简单功能:



命令& -在后台

作业中运行命令-打印后台命令列表



一个简单的示例,它无用。从test.txt文件中读取数字,并并行启动3个进程,它们休眠相应的秒数。每三秒钟检查一次正在运行的进程,如果少于三个,则启动一个新进程。后台进程的启动已移至单独的功能mytask,但是您可以直接在循环中启动它。



test.sh
#!/bin/bash 

NJOBS=3 ; export NJOBS

function mytask () {
echo sleeping for $1
 sleep $1
}

for i in $( cat test.txt )
do
    while [  $(jobs | wc -l ) -ge $NJOBS ]
        do 
            sleep 3
        done
    echo executing task for $i
    mytask $i &
done

echo waiting for $( jobs | wc -l ) jobs to complete
wait




输入数据:



test.txt
60

50

30

21

12

13



注意循环后的等待,该命令等待在后台运行的进程完成。没有它,脚本将在循环结束后立即终止,并且所有后台进程都将被中断。也许在著名的模因中提到了这种等待,“哦,等待!!!”。



终止后台进程



如果使用Ctrl-C中断脚本,它将被所有后台进程杀死。终端中运行的所有进程都从键盘(例如,SIGINT)接收信号。如果使用kill命令从另一个终端中杀死了脚本,则后台进程将一直运行直到终止,您需要记住这一点。



扰流板头
user@somehost ~/tmp2 $ ps -ef | grep -E «test|sleep»

user 1363 775 0 12:31 pts/5 00:00:00 ./test.sh

user 1368 1363 0 12:31 pts/5 00:00:00 ./test.sh

user 1370 1368 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 60

user 1373 1363 0 12:31 pts/5 00:00:00 ./test.sh

user 1375 1373 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 50

user 1378 1363 0 12:31 pts/5 00:00:00 ./test.sh

user 1382 1378 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 30

user 1387 1363 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 3

user 1389 556 0 12:31 pts/2 00:00:00 grep --colour=auto -E test|sleep

user@somehost ~/tmp2 $ kill 1363

user@somehost ~/tmp2 $ ps -ef | grep -E «test|sleep»

user 1368 1 0 12:31 pts/5 00:00:00 ./test.sh

user 1370 1368 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 60

user 1373 1 0 12:31 pts/5 00:00:00 ./test.sh

user 1375 1373 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 50

user 1378 1 0 12:31 pts/5 00:00:00 ./test.sh

user 1382 1378 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 30

user 1399 556 0 12:32 pts/2 00:00:00 grep --colour=auto -E test|sleep



可以通过截获必要的信号来处理这种情况,为此,我们在脚本的开头添加了一个处理程序:



陷阱
function pids_recursive() {
    cpids=`pgrep -P $1|xargs`
    echo $cpids
    for cpid in $cpids;
       do
          pids_recursive $cpid
       done
}

function kill_me () {
    kill -9 $( pids_recursive $$ | xargs )
    exit 1
}

# 
#trap 'echo trap SIGINT; kill_me ' SIGINT
trap 'echo trap SIGTERM; kill_me' SIGTERM




kill -L显示现有信号列表,如有必要,可以为所需信号添加处理程序。



All Articles