说到 shell 可控多线程,网上分享的大部分是管道控制的方案。这种方案,张戈博客也曾经实战并分享过一次:《Shell+Curl 网站健康状态检查脚本,抓出中国博客联盟失联站点》,感兴趣的朋友可以看看。
下面张戈博客再分享另一种更容易理解的入门级可控多线程 shell 脚本方案:任务切割、各个击破。
先来 1 段场景描述:
某日,在鹅厂接到了这个任务,需要在 Linux 服务器中,对几千个 IP 进行一次 Ping 检测,只要取得 ping 可达的 IP 就好。如果单个 IP 去 ping 测试,虽然也可以完成任务,几千个 IP 还好了,如果更多呢?
鉴于这个 case 简单程度,第一时间先放弃了以前用过的管道方案,而是采用了各个击破的思想。
简单思路:
按照任务切割的“战略思想”,我先将这几千 IP 存入一个 iplist 文件,然后写一个分割函数,将这个文件分成多份临时 IP 清单,最后,用多线程遍历这些临时 IP 文件即可变相实现多线程了。
具体代码:
#!/bin/sh #文本分割函数:将文本$1 按份数$2 进行分割 SplitFile() { linenum=`wc -l $1 |awk '{print $1}'` if [[ $linenum -le $2 ]] then echo "The lines of this file is less then $2, Are you kidding me..." exit fi Split=`expr $linenum / $2` Num1=1 FileNum=1 test -d SplitFile || mkdir -p SplitFile rm -rf SplitFile/* while [ $Num1 -lt $linenum ] do Num2=`expr $Num1 + $Split` sed -n "${Num1}, ${Num2}p " $1 > SplitFile/$1-$FileNum Num1=`expr $Num2 + 1` FileNum=`expr $FileNum + 1` done } #Define some variables SPLIT_NUM=${1:-10} #参数 1 表示分割成多少份即,开启多少个线程,默认 10 个 FILE=${2:-iplist} #参数 2 表示分割的对象,默认 iplist 文件 #分割文件 SplitFile $FILE $SPLIT_NUM #循环遍历临时 IP 文件 for iplist in $(ls ./SplitFile/*) do #循环 ping 测试临时 IP 文件中的 ip(丢后台) cat $iplist | while read ip do ping -c 4 -w 4 $ip >/dev/null && echo $ip | tee -ai okip.log #ping 可达的 IP 则写入日志 done & #在 while 循环后面加上&符号,让这个嵌套循环在后台执行 done
将代码保存为 ping.sh 之后,执行 sh ping.sh iplist 100 的过程如下:
先将 iplist 切割成 100 份,存放在 SplitFile 文件夹中
然后,通过 for 循环读取这些分割文件,并在后台使用 while 循环对其中 ip 执行 ping 命令。
由于 while 是丢后台的, 所以 for 循环会一次性执行 100 个 while,相当于开启了 100 个线程,速度自然不可同日而语矣。
其中,切割的份数即你想要开启的多线程数量,很明显,这种任务分割的思路虽然没有管道方案来的高大上,但是其思想更加简单易懂,而且通用性也更好,适合入门级的简单多线程任务。
这个表示看不懂,有了这个技术导航站检查是不是不要人工一个个点着看了啊
算是半自动吧
哎,没看懂,但是还是不间断的来学习,时间长了,也许会或多或少能学到些东西!
好专业的,不好喷。
博主除了会搞程序还会搞运维方面的东西?好了不起,不得不佩服,永远支持你
shell很牛呀
来给看看,也算是见识见了
好吧,看不懂代码,小白一枚飘过
你的博客导航里的那些死站清理了吗?
谢谢博主分享的文章。很棒。
张哥,代码有点不太明白...上面写着"#文本分割函数:将文本$1按份数$2进行分割"..但是到了引用函数的地方好像两个参数反过来了...还有一个问题是..如果按照一个文本20行的话..默认分开10份.按照函数的算法num1跟num2的组合分别如下:
n1=1 n2=3
n1=4 n2=6
n1=7 n2=9
n1=10 n2=12
n1=13 n2=15
n1=16 n2=18
n1=19 n2=21
好像并不是想象那么完美..我不知道有无理解错您脚本的意思..望回复
那个是函数的顺序,确实和脚本整个参数是反的:
SPLIT_NUM=${1:-10} #参数1表示分割成多少份即,开启多少个线程,默认10个
FILE=${2:-iplist} #参数2表示分割的对象,默认iplist文件
#分割文件
SplitFile $FILE $SPLIT_NUM
这里是为了我自己方便,因为我们这边iplist是默认的,所以只需要执行 1.sh + 分割的线程数,这里其实也可以用 -f file -t 10 这种模式获取。。。这是偷懒了
按照你说的,确实不完美、不严谨,可以试下 split -l 10 file.txt 这个来做份数切分,不过当无法整除的时候也是不严谨的
我可以转载吗?会原汁原味保留你的出处