Shell 腳本進程並發&進程數控制


Shell 都以串行的方式自上而下執行命令,不適用需要大量作業的場景。
學習此篇shell腳本進程並發,能夠大大提高工作效率~
通過wait 和 & 后台符號 可以實現並行,但無法控制進程數。

{
	task
}&
done
wait

{} 將主執行程序變為一個塊,使用&放入后台
wait 函數等待所有后台進程執行程序,否則繼續執行后續命令直到整個腳本結束

通過有名管道控制並發進程數

創建一個fifo文件, 作為進程池, 里面存放一定數目的"令牌".作業運行規則如下: 所有作業排隊依次領取令牌; 每個作業運行前從進程池中領取一塊令牌, 完成后再歸還令牌; 當進程池中沒有令牌時, 要運行的作業只能等待. 這樣就能保證同時運行的作業數等於令牌數.

管道 = = 》有名管道、無名(匿名)管道
有名管道:mkfilo 創建一個管道文件
有名管道: “cat 1.file | grep ‘xxx’ ” “|” ==》創建一個無名管道,直接作為兩個進程的數據通道

exec 自行定義,綁定文件操作符

系統默認三個文件操作符 0、1、2 = = 》 stdin、stdout、stderr
ls /proc/self/fd

模板

#!/bin/bash
trap "exec 6>&-;exec 6<&-;wxit 0" 2
#接受2 程序終止(interrupt)信號 "ctrl c" 后的操作。關閉fd6 
tmp_fifofile=/tmp/$$.fifo        //$$ 進程pid  
mkfifo $tmp_fifofile			 //創建為進程pid的管道
							   //我常用$((RANDOM)),大概率的避免與已有文件重復
exec 6<>$tmp_fifofile			//以6為文件描述符fd打開管道 <>代表讀寫
rm $tmp_fifofile
thread=250						//定義並發進程數量,上文的令牌數量
#在fd6中放入$thread 個空行作為令牌
for ((i=0; i<=$thread;i++))
do
  echo
done >&6
for i in ``                              //可以省略,直接在{}括號內添加執行命令
do
	read -u6                             //read 讀取行,領取令牌              
	{


	echo >& 6                            //歸還令牌
}&                                       //{ }&放入后台
done
wait                                     //等待所有后台子進程結束
exec 6>&-                                //關閉fd6
exec 6<&-                                //關閉fd6

結束

學術不精。歡迎評論一起討論!~

附上一個自己寫的使用並發,檢查大批量站點的域名檢測腳本
將待檢查的腳本放入指定目錄就行了~

#!/bin/bash

#創建今日目錄
if [ ! -d "./$(date +%y-%m-%d)" ];then
    mkdir -p /script/$(date +%y-%m-%d)
fi
dir=/script/$(date +%y-%m-%d)

function global()
{
#第一次curl檢測
tmp_fifofile=/tmp/$(($RANDOM%1000)).fifo
mkfifo $tmp_fifofile
exec 6<>$tmp_fifofile
rm $tmp_fifofile
thread=256
for ((i=0; i<=$thread;i++))
do
   echo
done >&6

for ((i=0;i<=$thread;i++))
do
    echo >&6
done

for i  in `cat /script/domain/$url`
do
   read -u6
   {
   code=$(curl -o /dev/null --retry 2 --connect-timeout 10 -s -w %{http_code} $i)
   echo "$code $i" >> $dir/$url-first.log
   echo >& 6
}&

done
wait
exec 6>&-
exec 6<&-
grep -v '200\|301\|302'  $dir/$url-first.log  |tail -n +2  |awk -F' ' '{print $2}' > $dir/$url-second.log
rm -f $dir/$url-first.log  
#第二次wget檢測
tmp_fifofile=/tmp/$(($RANDOM%1000)).fifo
mkfifo $tmp_fifofile
exec 6<>$tmp_fifofile
rm $tmp_fifofile
thread=128
for ((i=0; i<=$thread;i++))
do
   echo >&6
done

for i in `cat $dir/$url-second.log`
do
   read -u6
   {
    wget -T 10 --spider -t 2 $i &>/dev/null $i >> /dev/null
    if [ $? = 0 ];then
     echo $i >> /dev/null
    else
     echo $i >> $dir/$url-third.log
    fi
   echo >& 6
}&
done
wait
exec 6>&-
exec 6<&-
rm -f $dir/$url-second.log

#第三次curl檢測
tmp_fifofile=/tmp/$(($RANDOM%1000)).fifo
mkfifo $tmp_fifofile
exec 6<>$tmp_fifofile
rm $tmp_fifofile
thread=128
for ((i=0; i<=$thread;i++))
do
   echo >&6
done

for i  in `cat $dir/$url-third.log`
do
   read -u6
   {
   code=$(curl -o /dev/null --retry 2 --connect-timeout 10 -s -w %{http_code} $i)
   echo "$code $i" >> $dir/$url-fourth.log
   echo >& 6
}&

done
wait
exec 6>&-
grep -v '200\|301\|302'  $dir/$url-fourth.log  |tail -n +2   >> $dir/last.log
rm -f $dir/$url-third.log
rm -f $dir/$url-fourth.log

}

function last (){
grep -v '200\|301\|302' $dir/last.log |awk -F' ' '{print $2}' >> $dir/last2.log 
rm -f $dir/last.log
tmp_fifofile=/tmp/last.fifo
mkfifo $tmp_fifofile
exec 6<>$tmp_fifofile
rm $tmp_fifofile
thread=64
for ((i=0; i<=$thread;i++))
do
   echo
done >&6

for ((i=0;i<=$thread;i++))
do
    echo >&6
done


for i  in `cat $dir/last2.log`
do
   read -u6
   {
   code=$(curl -o /dev/null --retry 2 --connect-timeout 10 -s -w %{http_code} $i)
   echo "$code $i" >> $dir/last3.log
   echo >& 6
}&
done
wait
exec 6>&-
exec 6<&-
rm -f $dir/last2.log
echo "請手動復核以下域名:" > $dir/$(date +%H-00)domain.log
grep -v '200\|301\|302' $dir/last3.log >> $dir/$(date +%H-00)domain.log
rm -f $dir/last3.log
}


function main ()
{
tmp_fifofile=/tmp/main.fifo
mkfifo $tmp_fifofile
exec 8<>$tmp_fifofile
rm $tmp_fifofile
thread=2
for ((i=0; i<=$thread;i++))
do
   echo
done >&8

for url in `ls -l /script/domain/ | tail -n +2 | awk -F' ' '{print $9}'`
do
  read -u8
{
  global $url
  echo >& 8
}&

done
wait
exec 8>&-
exec 8<&-

}

main
last
mail -s "檢測結果來自xx服務器 :" xxxxxxxx@qq.com < $dir/$(date +%H-00)domain.log 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM