shell应用分享

shell应用分享

简介

  1. 本文目的
    是什么(what) 有什么好(why) 用武之地(where) 怎么学/用(how)

    • 简单介绍shell,对比几种常见shell,并推荐bash作为您工作学习的shell
    • 如何得到shell帮助
    • 快速用shell进行编程
    • 如何提高shell能力
    • shell应用案例分享
  2. 本文将不介绍以下内容,但您可以通过google很容易找到相关内容

    • 如何安装shell

shell简介

本章回答前三个问题(3W)

  1. shell是一个解释器(what)

    shell是linux/unix及其他类unix系统的下的解释器, 它提供了用户与系统交互的接口
    shell-kernel关系
    shell本质是一个linux进程,演示ps shell

  2. shell的种类

    • sh: Bourne Shell , 伯恩shell , 比较原始的shell, 极其精简,基本上所有类unix系统都有安装
    • bash: Bourne Again Shell , 伯恩shell加强版 , 兼容sh, 命令补全,文档丰富,社区活跃.
    • ksh: korn Shell , 科恩shell , 语法元素较丰富,文档较少,学习成本高
    • csh: ‘C’ Shell , 提供了与C语言相近的语法元素,比如if ( expr ), 并且还要尽量兼容sh,因此语法怪异
    • tcsh: 新一代 csh , 兼容csh , 提供命令补全
  3. shell推荐

    参考:shell比较

    ShellExperienceEditingShortcutsPortabilityLearning
    Bourne33311
    POSIX21212
    C22232
    Korn11222
    TC21133
    Bourne Again21123
    Z21133
  4. shell的优势(why)

    • 简单的输入输出模式
    • 管道
    • 通用性强
    • 程序重用
  5. shell干什么用(where)

    • 启停程序(调度)
    • 查看系统状态
    • 日志分析
    • 数据处理
    • 上传下载
    • 监控及调度
    • 调试测试
    • ……(太多,列不完)
    • 以上所有内容的组合

shell不适合干什么

作为应用场景的补充,这里说下哪些场景不适合用shell实现

  1. 计算密集型任务
  2. 高性能服务场景
  3. 复杂数据结构

shell怎么用(how)

  1. shell本质就是命令的堆砌
    shell逐行执行如下代码:
    命令 [参数]
    如:
    ls -lart
    cd /data
    which ls
    命令可以是shell内置的,也可以是外部程序
    内置命令如: cd , alias , source , jobs

  2. 如何获得帮助

    • shell本身帮助
      man bash

    • 程序帮助
      man <程序名>

    • 搜索帮助
      apropos 程序名|程序名的一部分

    • 阅读代码时不熟的命令或程序
      先apropos查看该命令或程序是否存在,不存在可能为命令,可在man bash里搜索

    • 借助搜索引擎
      google

  3. shell语法提要

    • 控制
    • 循环
    • 变量替换(Parameter Expansion)
    • 输入输出
    • 管道
    • 表达式执行(eval)
    • 函数
  4. shell语法

    1. 控制结构

      if test 1 -eq 2 ; then 
         echo "true" ; 
      fi
      
      if [ 1 -eq 2 ] ; then 
        echo "true" ; 
      fi

      其中test有两种表示方式,第二种比较常用。第二种需要注意[]前后都需要有空格。

    2. 循环结构

      • while 循环
      while [ expr ] ;
      do
          <commands>
      done
      
      • foreach循环
      for i in a b c
      do
          echo $i
          <commands>
      done
      
      • for 循环(类C)
      for (( i=0 ; i<3; i++ ))
      do
          echo $i
          <commands>
      done
      
      • case
      i=1
      case $i in
        1) <commands>
        break;;
        *2) <commands>
        break;;
        *) <commands>
      esac

      *是通配符,指代任意字符组合

    3. 变量替换
      也称为参数扩展,可以在man bash页中查找Parameter Expansion

      s="a/b%c#d"
      
      
      # 截头
      
      echo ${s#*/}
      
      
      # 去尾
      
      echo ${s%#*}
      echo ${s%\%*}

      % , # 成双时,表示贪婪模式
      \ 是转义字符, 当一个字符会产生歧义时,shell优先会将其当成控制字符,而非打印字符,用转义字符将之转为打印字符

    4. 输入输出

      • 输出到tty(stdout)
      echo "yy"
      cat file.txt
      • 输出重定向
      echo "yy"  > file.tmp
      cat file.txt >> file.tmp
      • 输入(stdin)
      while read token 
      do
          echo $token
      done
      • 输入重定向
      cat < file.tmp
      
      while read token 
      do
          echo $token
      done < file.tmp
    5. 管道
      将上一级命令的stdout绑定到下一级命令的stdin, 这就是管道。

      ls|grep txt$
      cat | awk '{print $2}'
    6. 表达式执行(eval)
      将一个文本当成命令执行,并获得其输出,就是表达式执行(eval)或称为表达式求值。
      有两种形式:

      • ``引起来,如:
      sum=`expr 1 + 2`
      echo $sum
      lastlog=`tail -1 some.log`
      echo $lastlog
      • $()引起来,如:
      pronum=$(ps -ef|grep nginx|grep -v grep|wc -l)
      echo $pronum
      • $(())引起来,这种表达式必须是数值计算的表达式如:
      mul = $(( 3 * 4 ))
      pow = $(( 2 ** 5 ))
      echo $mul $pow
    7. 自定义函数

      自定义函数可以当命令使用,如

      proc_search()
      {
          ps -ef|grep $1|grep -v grep
      }
      proc_search nginx
  5. shell进阶 - 常用工具软件

    shell大部分时候都要借助于工具来实现复杂功能。同时用shell来调用也能使软件实现更专业化,简单化

    • 计算器: bc
    • JSON: jq , js-beautify
    • 文件处理: grep ,awk , sed ,perl
    • 二进制处理: xxd , od
    • 二进制烧录: dd
    • 网络调试: nc, tcpdump ,wireshark, socat
  6. 执行脚本
    写完脚本,需要执行,脚本才会变的有意义,就如同赋予脚本生命。

    • 给脚本执行权限chmod +x ./script.sh
    • 执行./script.shbash ./script.sh
    • 对于./script.sh 这种执行方式, shell在调度时会查看被称为Shebang的行, 即脚本开头的#!/bin/sh, 告知(解释器)整体对待该文件的方式
  7. 环境变量
    这是脚本执行的另一个重要概念,环境变量会影响进程并传递给其子进程。如:
    LIBRARY_PATH
    LD_PRELOAD

shell应用场景及案例

掌握了shell的语法,接下来可以开始实战了
do one thing and do it well – Bash 的威力

  1. 批量重命名
    我们目录里有多个mp3文件,但其名字不够规范,我们想进行批量重命名
    执行该任务前,我们应该知道,mp3文件有tag信息,这些信息称为ID3, 通过搜索,我们知道id3tool这个工具可帮助我们从mp3的tag信息中获得唱片及演唱者信息。因此我们先安装下该软件apt-get install id3toolyum install id3tool

    rm -Rf rename_dir
    mkdir rename_dir
    cd rename_dir
    cp ../*.mp3 .
    
    for i in *.mp3
    do 
      title=`id3tool $i|grep -i title|awk -F: '{gsub(/\s/, "", $2);print $2}'`
      artist=`id3tool $i|grep -i artist|awk -F: '{gsub(/\s/, "", $2);print $2}'`
      mv $i "$artist - $title.mp3"
    done
  2. 环境构建
    为某个任务构建执行环境,解放双手,也方便新人上手
    如先进行数据库操作,然后调用客户端请求,再从数据库查询,检查服务是否正确更新数据
    示例:
    本例所处环境: 192.168.1.15:10081建立了一个web服务,并可响应host_list请求,并返回数据库中己创建的主机信息。 本例通过修改数据库,并使用curl工具进行测试修改是否生效。

    mysql -h192.168.1.12 -uroot -proot frame -A  --default-character-set=utf8 <<END
    update t_host set memo = "我们在测试" where host_id = 1 ;
    END
    
    cat > req.json <<END
    req={"head":{"cmd":3005,"xid":"99902565-22ad-4206-9a86-87af7ee27d4f"},"row_count":10,"offset":0}
    END
    
    urlbase="http://192.168.1.15:10081"
    reqpath="internal.host_list"
    ContentType="Content-Type: application/x-www-form-urlencoded"
    curl -vvv -H "$ContentType" -d @"req.json" $urlbase/$reqpath 
    
  3. 调试测试
    本例以docker启动一个memcache作为例子,演示如何通过nc工具,进行测试tcp服务。

    docker run -d --name memcached \
          -p 11311:11211/tcp \
          memcached:1.5.9-alpine \
          memcached -m 64
    
    printf "set mykey 0 60 4\r\ndata\r\n" | nc 192.168.1.15 11311
    printf "get mykey\r\n" |nc 192.168.1.15 11311
  4. 屏蔽复杂性
    当你拿到一个抓包结果文件130.pcap要分析丢包情况,过去你是怎么做的?在wireshark里肉眼看?还是对着libpcap的开发文档写一个专用的程序(你可能要写filter,dissector,然后还要做数据聚合)?
    以上任一种方法估计今天的任务,明天未必能完成。
    这里给出一个非常方便的套路,你甚至都不用了解pcap的结构。
    130.pcap是我们在130机器上抓的syn包,以下脚本用来分析syn丢包情况:

    pcap_extract_syn_ack(){
        # 参数1: pcap 文件
    
        # 输出为: 1532536078.101 0
        #         1532536078.509 1
    
        tshark -r $1 \
            # 过滤器: syn 和 syn ack包
            -2R "tcp.flags.syn != 0" \
            # 指定输出域
            -T fields -e 'frame.time_epoch'  -e 'tcp.flags.ack' 
    }
    
    join_syn_ack_filter() {
        # 管道过滤器
        # 输入为: 1532536078.101 0
        #         1532536078.509 1
    
        # 输出为: 1532536078.101|0|1532536078.509|1
    
        awk '{
            if($2==0) {
              rtrim;
              printf "\n%s|%s",$1,$2}
            else{
              printf "|%s|%s\n",$1,$2}  }' 
    }
    
    statistic_syn_ack_filter() {
        # 输入为: 1532536078.101|0|1532536078.509|1
        #    或:  1532536079.101|0
        #    或:  |1532536079.509|1
    
        # 输出为: 按分钟统计的未匹配结果
    
        awk -F| 'NF==2{ 
            sum[$1 - $1 % 60] ++
          }END{
            for (i in sum)
            {
                print strftime("%Y-%m-%d %H:%M:00",i) ,"\t",sum[i]
            } }' 
    }
    
    pcap_extract_syn_ack 130.pcap |\
        join_syn_ack_filter |\
        statistic_syn_ack_filter
    

    借助于强大的管道,可以让程序只专注于一个领域的功能, 复杂功能就靠这样组合出来。 借助tshark输出指定字段,还有两级管道。可以看到每个部分只处理极小且简单的任务。

  5. shell cgi

    编写脚本/usr/lib/cgi-bin/env.cgi

    
    #!/bin/bash
    
    echo -e "Content-type: text/html\n\n"
    
    /bin/cat << EOM 
    <HTML>
    <HEAD>
        <TITLE>env</TITLE>
    </HEAD>
    <BODY bgcolor="#cccccc" text="#000000">
        <P> 
        <SMALL>
        <PRE>
    EOM
    
    /usr/bin/env
    
    /bin/cat << EOM 
        </PRE>
        </SMALL>
        </P> 
    </BODY>
    </HTML>
    EOM

    docker run -it -p 8001:80/tcp debian:jessie-20180625 bash
    在docker命令行下执行以下代码:

    cat > /etc/apt/sources.list <<END
    deb http://mirrors.163.com/debian stretch main
    deb http://mirrors.163.com/debian stretch-updates main
    deb http://mirrors.163.com/debian jessie main contrib non-free
    deb http://mirrors.163.com/debian jessie-updates main
    END
    
    cat >> /etc/apt/apt.conf.d/01proxy <<END
    Acquire::HTTP::Proxy "http://192.168.1.15:3142";
    Acquire::HTTPS::Proxy "false";
    END
    
    apt-get update && apt-get install vim-tiny apache2
    
    a2enmod cgi
    touch /usr/lib/cgi-bin/env.cgi
    chmod +x /usr/lib/cgi-bin/env.cgi
    chown www-data /usr/lib/cgi-bin/env.cgi
    service apache2 restart

    可以访问了:
    curl http://localhost:8001/cgi-bin/env.cgi

  6. 监视文件变更

    监视目录变更,并同步更新到另一台主机

    
    #!/sbin/bash
    
    
    host=192.168.1.53
    src=/data/admin
    dst=/data/admin
    user=root
    export PATH=$PATH:/usr/local/inotify-3.20.1/bin
    
    if [ ! -e "$src" ] \
         ||[ ! -e "${inotify_home}/bin/inotifywait" ] \
         ||[ ! -e "/usr/bin/rsync" ];
    then
        echo "Check File and Folder"
        exit 9
    fi
    
    inotifywait -mrq -e close_write,delete,create,attrib $src | while read files;
    do
        cd $src && /usr/bin/rsync -vrtapogL -R --delete ./ --timeout=100 $user@$host01:$dst 
    done

推荐阅读

bash最佳实践

鸣谢

感谢 pyclear , zhangguanzhang 为本文提供案例

参考

Bash 的威力
Basic Shell Reference Guide

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值