Linux系统下使用shell“多线程执行命令”

前言

在工作中常遇到如下场景:
系统未接入日志中心,系统本身使用集群部署,那么再查找日志的时候只能一台一台的去搜索关键字,后来运维同学发现这样一台一台效率太低了,于是有了升级版,升级之后的方式还是一台一台去搜索只不过这次换成了脚本去执行,原理上还是需要在一台上搜索完成之后再去另一台搜素。如果遇到日志相当多的情况,那这种也会很慢。

下面介绍一种今天新学到的技能,就是使用“多线程”的方式去执行脚本,但是这种多线程并不是类似java中的那种多线程,而是触发了多个进程,这里的多线程可以理解为多进程。

管道

在介绍多进程前,先来学习一下管道,一般说到管道,常使用Linux的同学首先会想到“|”,这个管道的意思是将前面的输出通过管道做为后面的输入,可以理解为是一种传输介质,是Linux的一种通信方式,比如ps -ef | grep test 。

那么还有一种管道是FIFO文件,这种文件也可以完成类似上面的工作,比如 ps -ef > .fifo写入文件, 同时在开个客户端就可以获取到通过如下命令获取到数据,grep test .fifo,实际操作一次会发现在写入文件后,如果另一个客户端不对.fifo做任何操作,那么第一个客户端会阻塞住,直到第二个客户端操作了之后第一个才会结束。

FIFO管道文件和普通文件的区别

1、创建方式不同
FIFO管道文件是通过mkfifo命令创建出来的,而普通文件是通过touch命令创建出来的
2、普通文件写入后不会阻塞,FIFO文件写入后会阻塞
3、普通文件时保存在磁盘上的,而FIFO文件是保存在内存中的

“多线程”的实现思路

初级版本:使用&符配合wait实现,这种适用于确定循环次数并且循环次数不是太多。

for ((i=0;i<5;i++));do
 
  echo 1
  {
    sleep 3;
    echo "done!"
  }&
done

wait
echo "执行完毕!!!"

升级版本:利用FiFO管道来控制进程数,达到了“多线程”且线程数可控的目的。
如下脚本中的open_thread()函数还可以封装成一个单独的脚本,使用的时候通过source xxx引入来使用,这样看起来更优雅一些。

#!/usr/bin/env bash

###################################################
# Describe: grep指定文件夹中的所有文本中的指定关键字 #
# Version: v1.0                                   #
# Author: cz                                      #
###################################################

# 开启多线程操作
open_thread() {
  # 最大进程数
  PROCESS_NUM=$1
  # 使用mkfifo命令可以使用指定的名称创建先进先出文件(FIFO)
  # 创建一个fifo文件
  FIFO_FILE=./$.fifo
  mkfifo $FIFO_FILE

  # 关联fifo文件和fd6
  exec 6<>$FIFO_FILE      # 将fd6指向fifo类型
  rm $FIFO_FILE

  # 向fd6中输入$PROCESS_NUM个回车
  echo ${PROCESS_NUM}
  for((idx=0;idx<${PROCESS_NUM};idx++))
  do
    echo
  done >&6

}

# 指定文件夹下的文件并行读取
# 支持 grep key_word file_name
#
#
grep_specified_folder () {

  echo $1
  echo $2
  echo $3
  # 获取指定文件夹
  folder=$1
  # 需要grep的关键字
  key_word=$2
  # 定义线程数,如果未定义则默认为5,如何判断是未定义呢,通过参数个数来判断
  PROCESS_NUM=$3
  # 临时文件名
  temporary_file_name='~jef_temp_file'
  # 开启多线程
  open_thread $3

  for filename in $(ls $folder)
    do
      read -u6
      # 每个线程处理一个gerp
      {
        result=`grep $key_word $folder/$filename`
        # 将结果追加到文件中
        echo "=============="$filename"===========" >> $temporary_file_name
        echo "$result" >> $temporary_file_name
        # 当进程结束以后,再向fd6中加上一个回车符,即补上了read -u6减去的那个
        echo  >&6
      }&
    done

  # 等待所有的任务执行完毕
  wait

  # 关闭fd6
  exec 6>&-

  cat $temporary_file_name
  rm $temporary_file_name
}

grep_specified_folder $1 $2 $3

你可能感兴趣的:(linux,服务器,bash)