shell本身是不能实现多线程的,但是可以通过启动子进程,并将子进程放入后台执行来模拟多线程,为了在提高脚本执行效率的同时又不明显增加负载的作用,还需要对同时放入后台的进程数做下限制。

#!/bin/bash
set -x  # 开启调试模式

#判断是否有参数
if [ $# != 1 ];then
    echo "您输入的参数有误"
    exit -1
fi

# 允许的最大进程数
MAX_THREAD_NUM=5

tmp_fifo_file=/tmp/$$.fifo # 以脚本运行的当前进程ID号作为文件名
mkfifo "$tmp_fifo_file"    # 新建一个随机fifo管道文件
exec 9<>"$tmp_fifo_file"   # 定义文件描述符9指向这个fifo管道文件
rm "$tmp_fifo_file"

# 预先写入指定数量的换行符到fifo管道文件中,一个换行符代表一个进程
for((i=0;i<$MAX_THREAD_NUM;i++));do
     echo 
done >&9

# 循环读出url并判断状态码
while read line
do
{
    # 进程控制
    read -u 9 # 从文件描述符9中读取行,实际指向fifo管道
    {
        isok=`curl -I -L -m 60 -o /dev/null -s -w %{http_code} $line`
        if [ "$isok" = "200" ];then
            echo $line "OK"
        else
            echo $line $isok
        fi
        echo >&9 # ,当前进程结束,往fifo管道文件中写入一个空行
    }&
}
done < $1 wait echo '执行结束' exec 9>&- # 删除文件描述符9

exit 0

脚本的任务是对一个url列表中的网址进行判断,判断这些网址是否可以继续访问,具体方法是,通过curl获取http的状态码来判断。

上面红色部分{}中的语句被放进子进程中在后台执行,当fifo中5个空行读完后,循环继续等待 read 中读取fifo数据,当后台的子进程完成任务后,排队往fifo输入空行,这样fifo中又有了数据,循环继续执行。

下面看看shell执行的结果

# bash scanUrl.sh url.txt 
+ '[' 1 '!=' 1 ']'
+ MAX_THREAD_NUM=5
+ tmp_fifo_file=/tmp/21510.fifo
+ mkfifo /tmp/21510.fifo
+ exec
+ rm /tmp/21510.fifo
+ (( i=0 ))
+ (( i<5 ))
+ echo
+ (( i++ ))
+ (( i<5 ))
+ echo
+ (( i++ ))
+ (( i<5 ))
+ echo
+ (( i++ ))
+ (( i<5 ))
+ echo
+ (( i++ ))
+ (( i<5 ))
+ echo
+ (( i++ ))
+ (( i<5 ))
+ read line
+ read -u 9
++ curl -I -L -m 60 -o /dev/null -s -w '%{http_code}' http://1986tp.cn/
+ read line
+ read -u 9
++ curl -I -L -m 60 -o /dev/null -s -w '%{http_code}' http://20xue.com/
+ read line
+ read -u 9
++ curl -I -L -m 60 -o /dev/null -s -w '%{http_code}' http://361a.net/
+ read line
+ read -u 9
++ curl -I -L -m 60 -o /dev/null -s -w '%{http_code}' http://42.hcocoa.com/
+ read line
+ read -u 9
++ curl -I -L -m 60 -o /dev/null -s -w '%{http_code}' http://50vip.com/
+ read line
+ read -u 9      # fifo文件中的5个空行读完了,等待其它子进程写入fifo
+ isok=200
+ '[' 200 = 200 ']'
+ echo http://20xue.com/ OK
http://20xue.com/ OK
+ echo          # 这个子进程完成任务,写入fifo一个空行,启动一个子进程
++ curl -I -L -m 60 -o /dev/null -s -w '%{http_code}' http://52ixwebhosting.com/
+ read line
+ read -u 9
+ isok=200
+ '[' 200 = 200 ']'
+ echo http://50vip.com/ OK
http://50vip.com/ OK
+ echo
++ curl -I -L -m 60 -o /dev/null -s -w '%{http_code}' http://52think.me/info/
+ read line
+ read -u 9
+ isok=200
+ '[' 200 = 200 ']'
+ echo http://361a.net/ OK
http://361a.net/ OK
+ echo
++ curl -I -L -m 60 -o /dev/null -s -w '%{http_code}' http://5imovie.org/
+ read line
+ wait         # 输入文件中的url都已经处理完成或在子进程中处理,等待所有子进程结束
+ isok=200
+ '[' 200 = 200 ']'
+ echo http://1986tp.cn/ OK
http://1986tp.cn/ OK
+ echo
+ isok=000
+ '[' 000 = 200 ']'
+ echo http://5imovie.org/ 000
http://5imovie.org/ 000
+ echo
+ isok=200
+ '[' 200 = 200 ']'
+ echo http://52ixwebhosting.com/ OK
http://52ixwebhosting.com/ OK
+ echo
+ isok=404
+ '[' 404 = 200 ']'
+ echo http://52think.me/info/ 404
http://52think.me/info/ 404
+ echo
+ isok=000
+ '[' 000 = 200 ']'
+ echo http://42.hcocoa.com/ 000
http://42.hcocoa.com/ 000
+ echo
+ echo $'\346\211\247\350\241\214\347\273\223\346\235\237'
执行结束
+ exec
+ exit 0

转载请注明:知识蚂蚁 » shell模拟多线程执行任务详解

我来说说

(便于我们更好的交流)

有不明白的地方欢迎留言哦~
取消