shell脚本_shell脚本学习 - CSDN
shell脚本 订阅
Shell Script [1]  ,Shell脚本与Windows/Dos下的批处理相似,也就是用各类命令预先放入到一个文件中,方便一次性执行的一个程序文件,主要是方便管理员进行设置或者管理用的。但是它比Windows下的批处理更强大,比用其他编程程序编辑的程序效率更高,它使用了Linux/Unix下的命令。 展开全文
Shell Script [1]  ,Shell脚本与Windows/Dos下的批处理相似,也就是用各类命令预先放入到一个文件中,方便一次性执行的一个程序文件,主要是方便管理员进行设置或者管理用的。但是它比Windows下的批处理更强大,比用其他编程程序编辑的程序效率更高,它使用了Linux/Unix下的命令。
信息
外文名
Shell
领    域
计算机
中文名
Shell脚本
性    质
名词
Shell脚本基本介绍
换一种说法也就是,shell script是利用shell的功能所写的一个程序,这个程序是使用纯文本文件,将一些shell的语法与指令写在里面,然后用正规表示法,管道命令以及数据流重导向等功能,以达到我们所想要的处理目的。更明白地来说,shell script就像早期dos年代的.bat,最简单的功能就是将许多指令汇整写一起,让使用者很容易地就能够一个操作执行多个命令,而shell script更是提供了数组,循环,条件以及逻辑判断等重要功能,让使用者可以直接以shell来写程序,而不必使用类似C程序语言等传统程序编写的语法。
收起全文
精华内容
参与话题
  • 收藏!一篇教会你写90%的shell脚本

    万次阅读 多人点赞 2020-08-21 17:25:45
    还不会写shell脚本?这篇文章教会你写90%的shell脚本

    在公司项目的开发过程中,需要编写shell脚本去处理一个业务,在编写过程中发现自身对shell脚本的知识不够完善,顾整理一下,本文章主要内容来自菜鸟教程 , 也添加了一些知识点

    看完这边文章应该就可以独立完成大部分脚本得编写

    shell脚本?

    在说什么是shell脚本之前,先说说什么是shell。

    shell是外壳的意思,就是操作系统的外壳。我们可以通过shell命令来操作和控制操作系统,比如Linux中的Shell命令就包括ls、cd、pwd等等。总结来说,Shell是一个命令解释器,它通过接受用户输入的Shell命令来启动、暂停、停止程序的运行或对计算机进行控制。

    shell 是一个应用程序,它连接了用户和 Linux 内核,让用户能够更加高效、安全、低成本地使用 Linux 内核,这就是 Shell 的本质。

    shell 本身并不是内核的一部分,它只是站在内核的基础上编写的一个应用程序。

    那么什么是shell脚本呢?

    shell脚本就是由Shell命令组成的执行文件,将一些命令整合到一个文件中,进行处理业务逻辑,脚本不用编译即可运行。它通过解释器解释运行,所以速度相对来说比较慢。

    shell脚本中最重要的就是对shell命令的使用与组合,再使用shell脚本支持的一些语言特性,完成想要的功能。

    博主所有文章首发在CSDN 和 公众号:【匠心Java

    【匠心Java】公众号分享工作中涉及到的技术知识,主要分享数据库相关和Java技术干货(JVM+并发+全链路优化);涉及计算机网络、数据结构与算法、linux等编程知识;

    微信扫描下述二维码关注;或微信搜索“匠心Java*”关注,期待与大家的交流

    匠心Java*

    注释

    “# ”开头的就是注释,被编译器忽略

    • 单行注释: #
    • 多行注释: :<<EOF … EOF 或者 :<<! … ! (:<< 标识多行注释开始,并指定一个标识符作为开始结束的标志)

    变量

    变量类型
    运行shell时,会同时存在三种变量:

    1. 局部变量:局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
    2. 环境变量:所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
    3. shell变量:shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行

    变量操作

    • 创建普通变量: name=“test” (=两边不可有空格)
    • 创建只可函数体中使用的局部变量: local name=“test” (使用local修饰的变量在函数体外无法访问,并且local只能在函数体内使用)
    • 使用变量: echo $name 或者 echo ${name} (推荐使用大括号版)
    • 变量重新赋值: name=“new_test” (将原值覆盖)
    • 只读变量: name=“only_read” -> readonly name (使用readonly标识后的变量,不可被修改)
    • 删除变量: unset name; (删除之后不可访问,删除不掉只读变量)

    字符串变量
    1)单引号

    • 单引号变量var='test' ,只能原样输出,变量无效
    • 单引号中不能出现一个单独的单引号,转义也不可以

    2)双引号

    • 双引号变量var="my name is ${name}",变量有效
    • 可出现转义符

    3)拼接字符串

    • 中间无任何+,之类的字符
    • name=“this is”" my name"; name=“this is my name”; name=“this” is “my name” 等效
    • name=‘this is’’ my nam’; name=‘this is my name’; name=‘this’ is ‘my name’ 等效

    4)获取字符串长度

    • 在${}中使用“#”获取长度
    • name=“test”;
    • echo ${#name}; # 输出为4

    5)提取子字符串

    • 1:4 从第2个开始 往后截取4个字符
    • ::4 从第一个字符开始 往后截取4个字符
    • name=“this is my name”;
    • echo ${name:1:4} #输出 his
    • echo ${name::4} #输出 this

    数组

    bash只支持一维数组,不支持多维数组

    • 定义数组:array_name=(li wang xiang zhang) (小括号做边界、使用空格分离)
    • 单独定义数组的元素: array_para[0]=“w”; array_para[3]=“s” (定义时下标不连续也可以)
    • 赋值数组元素:array_name[0]=“zhao”;
    • 获取数组元素:
      • array_name[0]=“li”
      • array_name[3]=“zhang”
      • echo ${array_name[0]} # 输出"li"
      • echo ${array_name[1]} # 输出" "
      • echo ${array_name[3]} # 输出"zhang"
      • echo ${array_name[@]} # 输出"li zhang" 输出数组所有元素,没有元素的下标省略
    • 取得元素个数:${#array_name[@]} 或者 ${#array_name[*]}
    • 取得单个元素长度:${#array_name[1]}

    参数传递

    • 获取参数值:
      • $0 : 固定,代表执行的文件名
      • $1 : 代表传入的第1个参数
      • $n : 代表传入的第n个参数
    • $#:参数个数
    • $*: 以一个单字符串显示所有向脚本传递的参数。如"$*“用「”」括起来的情况、以"$1 $2 … $n"的形式输出所有参数
    • $@:与$*相同,但是使用时加引号,并在引号中返回每个参数。
    • $$:脚本运行的当前进程号
    • $!:后台运行的最后一个进程的ID
    • $?: 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
    • $* 与 $@ 区别
      • 相同点:都是引用所有参数。
      • 不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 " * " 等价于 “1 2 3”(传递了一个参数),而 “@” 等价于 “1” “2” “3”(传递了三个参数)。

    运算符

    算数运算

    • + 、-、*、\ : 乘号前必须加\进行转义才可以进行乘法运算
    • 加法运算
      • val=`expr 2 + 2` (使用linux命令expr进行辅助运算)
      • val=$[2+2] (4个空格不是必要的,不同于条件判断)
      • val=$((2+2))

    数字关系运算符
    关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
    下面假定变量 a 为 10,变量 b 为 20

    • -eq :检测两个数是否相等,相等返回 true。 [ $a -eq $b ] 返回 false。
    • -ne: 检测两个数是否不相等,不相等返回 true。 [ $a -ne $b ] 返回 true。
    • -gt: 检测左边的数是否大于右边的,如果是,则返回 true。 [ $a -gt $b ] 返回 false。
    • -lt : 检测左边的数是否小于右边的,如果是,则返回 true。 [ $a -lt $b ] 返回 true。
    • -ge: 检测左边的数是否大于等于右边的,如果是,则返回 true。 [ $a -ge $b ] 返回 false。
    • -le : 检测左边的数是否小于等于右边的,如果是,则返回 true。 [ $a -le $b ] 返回 true。

    字符串运算符
    下表列出了常用的字符串运算符,假定变量 a 为 “abc”,变量 b 为 “efg”:

    • = :检测两个字符串是否相等,相等返回 true。 [ $a = $b ] 返回 false。
    • != :检测两个字符串是否相等,不相等返回 true。 [ $a != $b ] 返回 true。
    • -z :检测字符串长度是否为0,为0返回 true。 [ -z $a ] 返回 false。
    • -n :检测字符串长度是否为0,不为0返回 true。 [ -n “$a” ] 返回 true。
    • $ :检测字符串是否为空,不为空返回 true。 [ $a ] 返回 true。

    布尔运算符
    下表列出了常用的布尔运算符,假定变量 a 为 10,变量 b 为 20:

    • ! :非运算,表达式为 true 则返回 false,否则返回 true。 [ ! false ] 返回 true。
    • -o :或运算,有一个表达式为 true 则返回 true。 [ $a -lt 20 -o $b -gt 100 ] 返回 true。
    • -a :与运算,两个表达式都为 true 才返回 true。 [ $a -lt 20 -a $b -gt 100 ] 返回 false。

    逻辑运算符
    以下介绍 Shell 的逻辑运算符,假定变量 a 为 10,变量 b 为 20:

    • && :逻辑的 AND [[ $a -lt 100 && $b -gt 100 ]] 返回 false
    • || :逻辑的 OR [[ $a -lt 100 || $b -gt 100 ]] 返回 true

    文件运算符

    • -b file :检测文件是否是块设备文件,如果是,则返回 true。 [ -b $file ] 返回 false。
    • -c file :检测文件是否是字符设备文件,如果是,则返回 true。 [ -c $file ] 返回 false。
    • -d file :检测文件是否是目录,如果是,则返回 true。 [ -d $file ] 返回 false。
    • -f file :检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 [ -f $file ] 返回 true。
    • -g file :检测文件是否设置了 SGID 位,如果是,则返回 true。 [ -g $file ] 返回 false。
    • -k file :检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 [ -k $file ] 返回 false。
    • -p file :检测文件是否是有名管道,如果是,则返回 true。 [ -p $file ] 返回 false。
    • -u file :检测文件是否设置了 SUID 位,如果是,则返回 true。 [ -u $file ] 返回 false。
    • -r file :检测文件是否可读,如果是,则返回 true。 [ -r $file ] 返回 true。
    • -w file :检测文件是否可写,如果是,则返回 true。 [ -w $file ] 返回 true。
    • -x file :检测文件是否可执行,如果是,则返回 true。 [ -x $file ] 返回 true。
    • -s file :检测文件是否为空(文件大小是否大于0),不为空返回 true。 [ -s $file ] 返回 true。
    • -e file :检测文件(包括目录)是否存在,如果是,则返回 true。 [ -e $file ] 返回 true。

    执行相关

    命令替换
    命令替换与变量替换差不多,都是用来重组命令行的,先完成引号里的命令行,然后将其结果替换出来,再重组成新的命令行。
    执行命令:

    1. `ls /etc` : 反引号 (所有的unix系统都支持)
    2. $(ls /etc) : $+() (部分unix系统不支持)
      多个嵌套使用时,从内向外执行

    for file in \s /etc\ 或 for file in $(ls /etc) 循环中使用
    `dirname $0` 获取脚本文件所在的目录
    path=$(cd `dirname $0`;pwd) : 获取脚本当前所在目录,并且执行cd命令到达该目录,使用pwd获取路径并赋值到path变量

    算术运算

    1. $[ ] : 加减乘除,不必添加空格
    2. $(( )) :加减乘除等,不必添加空格

    逻辑判断

    1. [ ] : 中括号旁边和运算符两边必须添加空格 (可以使用,不推荐)
    2. [[ ]]:中括号旁边和运算符两边必须添加空格 (字符串验证时,推荐使用)
    3. (()) : 中括号旁边和运算符两边必须添加空格 (数字验证时,推荐使用)
    4. [[]] 和 (()) 分别是[ ]的针对数学比较表达式和字符串表达式的加强版。
    5. 使用[[ … ]]条件判断结构,而不是[ … ],能够防止脚本中的许多逻辑错误。比如,&&、||、<和> 操作符能够正常存在于[[ ]]条件判断结构中,但是如果出现在[ ]结构中的话,会报错。比如可以直接使用if [[ $a != 1 && $a != 2 ]], 如果不适用双括号, 则为if [ $a -ne 1] && [ $a != 2 ]或者if [ $a -ne 1 -a $a != 2 ]。
      [[ ]]中增加模式匹配特效;
      (( ))不需要再将表达式里面的大小于符号转义,除了可以使用标准的数学运算符外,还增加了以下符号
      在这里插入图片描述

    输出

    echo
    仅用于字符串的输出,没有使用printf作为输出的移植性好,建议使用printf

    printf

    printf 不会像 echo 自动添加换行符,我们可以手动添加 \n
    无大括号,直接以空格分隔

    • 格式:printf format-string [arguments...] 其中(format-string: 格式控制字符串、arguments: 参数列表)
    • 案例:printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
    • %s %c %d %f 都是格式替代符
      • d:Decimal 十进制整数 对应位置参数必须是十进制整数,否则报错!
      • s:String 字符串 对应位置参数必须是字符串或者字符型 否则报错
      • c:Char 字符 对应位置参数必须是字符串或者字符型 否则报错
      • f:Float 浮点 对应位置参数必须是数字型 否则报错
    • %-10s : 指一个宽度为10个字符(-表示左对齐,没有则表示右对齐),任何字符都会被显示在10个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。
    • %-4.2f :指格式化为小数,宽度为4个字符,其中.2指保留2位小数。
    • 转义符:
      • \a :警告字符,通常为ASCII的BEL字符
      • \b :后退
      • \c :抑制(不显示)输出结果中任何结尾的换行字符(只在%b格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略
      • \f :换页(formfeed)
      • \n :换行
      • \r :回车(Carriage return)
      • \t :水平制表符
      • \v :垂直制表符
      • \ :一个字面上的反斜杠字符
      • \ddd :表示1到3位数八进制值的字符。仅在格式字符串中有效
      • \0ddd :表示1到3位的八进制值字符

    流程控制

    和Java、PHP等语言不一样,sh的流程控制不可为空,即if或者else的大括号中无任何语句
    if else

    • if
    if condition
    then
        command1 
        command2
        ...
        commandN 
    fi
    
    • if else
    if condition
    then
        command1 
        command2
        ...
        commandN
    else
        command
    fi
    
    • if else-if else
    if condition1
    then
        command1
    elif condition2 
    then 
        command2
    else
        commandN
    fi
    

    for

    for var in item1 item2 ... itemN
    do
        command1
        command2
        ...
        commandN
    done
    

    while

    • while condition
    while condition
    do
        command
    done
    
    • while 无限循环
    while :
    do
        command
    done
    

    until
    until 循环执行一系列命令直至条件为 true 时停止。
    until 循环与 while 循环在处理方式上刚好相反。

    until condition
    do
        command
    done
    

    case
    Shell case语句为多选择语句。可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。
    case需要一个esac(就是case反过来)作为结束标记,每个case分支用右圆括号,用两个分号表示break,其中“;;”不是跳出循环,是不在去匹配下面的模式
    case语句格式如下:

    casein
      模式1)
        command1
        command2
        ...
        commandN
        ;;
      模式2)
        command1
        command2
        ...
        commandN
        ;;
    esac
    

    跳出循环

    1. break :跳出总循环
    2. continue:跳出当前循环,继续下一次循环

    定义函数

    可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。

    • 函数定义
    [ function ] funname()
    {
        action;
        [return int;]
    }
    
    • 参数传递
      • 调用函数: fun_name 2 3 4
      • 函数中使用:和shell取用函数相同 $n $# $* $? 或者加上{}
    funWithParam(){
        echo "第一个参数为 $1 !"
        echo "第二个参数为 $2 !"
        echo "第十个参数为 $10 !"
        echo "第十个参数为 ${10} !"
        echo "第十一个参数为 ${11} !"
        echo "参数总数有 $# 个!"
        echo "作为一个字符串输出所有参数 $* !"}
    funWithParam 1 2 3 4 5 6 7 8 9 34 73
    echo $?  \# 判断执行是否成功
    
    • 函数返回值
      • return字样可存在也可不存在
      • return 只能为 return [0-255],此处的返回可作为函数执行的状态,通过$?获取的便是这个返回值
      • 如果不加return , 则默认最后一条语句的执行状态所为函数执行状态的返回值,如果最后一条语句执行成功,则$?为0,否则不为0
    • 使用函数返回值(Janusgraph图数据库官方启动服务脚本片段)
      • return返回的数字,只是作为函数执行状态的返回值,也就是接下来$?获取的值
      • 对于类似于下面的BIN=\abs_path``语句,获取的是函数体内所有的echo、printf输出组合成的一个字符串
    abs_path() {
        SOURCE="${BASH_SOURCE[0]}"
        while [ -h "$SOURCE" ]; do
            DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
            SOURCE="$(readlink "$SOURCE")"
            [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
        done
        echo "test"  
        echo "$( cd -P "$( dirname "$SOURCE" )" && pwd )"  
        # 此函数的两个echo输出会组合成一个字符串作为下述BIN的值
    }
    
    BIN=`abs_path` # BIN赋值函数返回值,如果没有return,则函数中所有的echo、printf输出组合成一个字符串传入BIN
    path=${BIN}/nodetool # 可直接使用
    

    输入输出重定向

    一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:

    • 标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。
    • 标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。
    • 标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。

    默认情况下,command > file 将 stdout 重定向到 file,command < file 将stdin 重定向到 file。
    如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null:

    输入重定向

    1. bash.sh < file : 将脚本的输入重定向到file,由file提供参数

    输出重定向

    1. bash.sh > file : 将脚本的输出数据重定向到file中,覆盖数据
    2. bash.sh >> file : 将脚本的输出数据重定向到file中,追加数据
    3. command >> file 2>&1 : 将 stdout 和 stderr 合并后重定向到 file

    读取外部输入

    命令:read arg (脚本读取外部输入并赋值到变量上)
    在shell脚本执行到上述命令时,停止脚本执行并等待外部输入,将外部输入赋值到arg变量上,继续执行脚本

    文件引用

    引用其他的文件之后,可以使用其变量、函数等等,相当于将引用的文件包含进了当前文件
    两种方式:

    1. . file_path\file_name
    2. source file_path\file_name

    颜色标识

    printf  "\033[32m SUCCESS: yay \033[0m\n";
    printf  "\033[33m WARNING: hmm \033[0m\n";
    printf  "\033[31m ERROR: fubar \033[0m\n";
    

    输出结果:
    在这里插入图片描述

    长句换行

    在shell中为避免一个语句过长,可以使用“\”进行换行
    使用“\”换行,在脚本执行过程中还是当做一行一个语句执行,不同于enter直接换行

    注意:\ 前添加一个空格 。 \ 后无空格直接换行。

     /mysql/bin/mysql \
      -h test_host  -P 000 \
      -u test_user -ptest_password ;
    

    shell操作mysql

    下面案例为登录mysql,并选择操作数据库,之后进行导入数据

     /mysql/mysql/bin/mysql \
      -h test_host  -P 000 \
      -u test_user -ptest_password \
      -e"use test_database; source data_faile; " # -e 代表执行sql语句
    

    -u 用户名
    -p 用户密码
    -h 服务器ip地址
    -D 连接的数据库
    -N 不输出列信息
    -B 使用tab键 代替 分隔符
    -e 执行的SQL语句

    退出脚本

    命令:exit

    在退出脚本时使用不同的错误码,这样可以根据错误码来判断发生了什么错误。

    在绝大多数 shell 脚本中,exit 0 表示执行成功,exit 1 表示发生错误。
    对错误与错误码进行一对一的映射,这样有助于脚本调试。

    命令:set -e 或者 set +e
    set -e表示从当前位置开始,如果出现任何错误都将触发exit。相反,set +e表示不管出现任何错误继续执行脚本。

    如果脚本是有状态的(每个后续步骤都依赖前一个步骤),那么请使用set -e,在脚本出现错误时立即退出脚本。
    如果要求所有命令都要执行完(很少会这样),那么就使用set +e。

    shell脚本调试

    检查是否有语法错误-n
    bash -n script_name.sh
    使用下面的命令来执行并调试 Shell 脚本-x
    bash -x script_name.sh
    调试count_odd_number.sh 程序案例:

    #!/usr/bin.env bash
    
    # 用于计算数组中奇数的和
    # @author liyangyang
    # @time 2019/09/17
    
    sum=0
    for num in 1 2 3 4;do
        re=${num}%2
        if (( ${re} == 1 ));then
            sum=$[${sum}+${num}]
        fi
    done
    echo ${sum}
    
    1. 首先检查有无语法错误:
      bash -n count_odd_number.sh
    2. 没有输出,说明没有错误,开始实际调试:
      bash -x count_odd_number.sh
    3. 调试结果如下:
    + sum=0
    + for num in 1 2 3 4
    + re=1%2
    + ((  1%2 == 1  ))
    + sum=1
    + for num in 1 2 3 4
    + re=2%2
    + ((  2%2 == 1  ))
    + for num in 1 2 3 4
    + re=3%2
    + ((  3%2 == 1  ))
    + sum=4
    + for num in 1 2 3 4
    + re=4%2
    + ((  4%2 == 1  ))
    + echo 4
    4
    

    其中的输出显示了程序执行的每一步,通过观察程序执行的步骤是否满足预期从而达到调试的效果
    带有 + 表示的是 Shell 调试器的输出,不带 + 表示程序的输出。

    案例:

    这是es(ElasticSearch)官方启动服务的脚本,看可不可以理解吧~

    #!/usr/bin/env bash
    
    # CONTROLLING STARTUP:
    #
    # This script relies on a few environment variables to determine startup
    # behavior, those variables are:
    #
    #   ES_PATH_CONF -- Path to config directory
    #   ES_JAVA_OPTS -- External Java Opts on top of the defaults set
    #
    # Optionally, exact memory values can be set using the `ES_JAVA_OPTS`. Note that
    # the Xms and Xmx lines in the JVM options file must be commented out. Example
    # values are "512m", and "10g".
    #
    #   ES_JAVA_OPTS="-Xms8g -Xmx8g" ./bin/elasticsearch
    
    source "`dirname "$0"`"/elasticsearch-env
    
    parse_jvm_options() {
      if [ -f "$1" ]; then
        echo "`grep "^-" "$1" | tr '\n' ' '`"
      fi
    }
    
    ES_JVM_OPTIONS="$ES_PATH_CONF"/jvm.options
    
    ES_JAVA_OPTS="`parse_jvm_options "$ES_JVM_OPTIONS"` $ES_JAVA_OPTS"
    
    # manual parsing to find out, if process should be detached
    if ! echo $* | grep -E '(^-d |-d$| -d |--daemonize$|--daemonize )' > /dev/null; then
      exec \
        "$JAVA" \
        $ES_JAVA_OPTS \
        -Des.path.home="$ES_HOME" \
        -Des.path.conf="$ES_PATH_CONF" \
        -cp "$ES_CLASSPATH" \
        org.elasticsearch.bootstrap.Elasticsearch \
        "$@"
    else
      exec \
        "$JAVA" \
        $ES_JAVA_OPTS \
        -Des.path.home="$ES_HOME" \
        -Des.path.conf="$ES_PATH_CONF" \
        -cp "$ES_CLASSPATH" \
        org.elasticsearch.bootstrap.Elasticsearch \
        "$@" \
        <&- &
      retval=$?
      pid=$!
      [ $retval -eq 0 ] || exit $retval
      if [ ! -z "$ES_STARTUP_SLEEP_TIME" ]; then
        sleep $ES_STARTUP_SLEEP_TIME
      fi
      if ! ps -p $pid > /dev/null ; then
        exit 1
      fi
      exit 0
    fi
    
    exit $?
    

    推荐阅读:
    Git-【技术干货】工作中Git的使用实践
    Git - 使用git不知道内部实现机制怎么行

    如果转载此博文,请附上本文链接,谢谢合作~ :https://blog.csdn.net/CSDN___LYY/article/details/100584638

    如果感觉这篇文章对您有所帮助,请点击一下“喜欢”或者“关注”博主,您的喜欢和关注将是我前进的最大动力!谢谢大家~

    在这里插入图片描述

    展开全文
  • Shell脚本详解---一篇搞定

    千次阅读 多人点赞 2018-10-04 18:06:54
    Shell脚本语言是实现Linux/UNIX系统管理及自动化运维所必备的重要工具, Linux/UNIX系统的底层及基础应用软件的核心大都涉及Shell脚本的内容。每一个合格 的Linux系统管理员或运维工程师,都需要能够熟练地编写Shell...

    有道云分享链接

    1.1 前言

    1.1.1 为什么学Shell

    Shell脚本语言是实现Linux/UNIX系统管理及自动化运维所必备的重要工具, Linux/UNIX系统的底层及基础应用软件的核心大都涉及Shell脚本的内容。每一个合格 的Linux系统管理员或运维工程师,都需要能够熟练地编写Shell脚本语言,并能够阅 读系统及各类软件附带的Shell脚本内容。只有这样才能提升运维人员的工作效率,适 应曰益复杂的工作环境,减少不必要的重复工作,从而为个人的职场发展奠定较好的基础

    1.1.2 什么是shell

    Shell是一个命令解释器,它在操作系统的最外层,负责直接与用户对话,把用户的输入解释给操作系统,并处理各种各样的操作系统的输出结果,输出屏幕返回给用户。

    这种对话方式可以是:

    交互的方式:从键盘输入命令,通过/bin/bash的解析,可以立即得到Shell的回应

    [root@clsn ~]# ls           
    anaconda-ks.cfg 
    [root@clsn ~]# echo ls |bash
    anaconda-ks.cfg  

    非交互的方式: 脚本

    1.1.3 什么是Shell脚本

      命令、变量和流程控制语句等有机的结合起来

             shell脚本擅长处理纯文本类型的数据,而linux中,几乎所有的配置文件,日志,都是纯文本类型文件

    1.1.4 脚本语言的种类

    一、编译型语言

    定义:指用专用的编译器,针对特定的操作平台(操作系统)将某种高级语言源代码一次性翻译成可被硬件平台直接运行的二进制机器码(具有操作数,指令、及相应的格式),这个过程叫做编译(./configure  make makeinstall );编译好的可执行性文件(.exe),可在相对应的平台上运行(移植性差,但运行效率高)。。

    典型的编译型语言有, C语言、C++等。

    另外,Java语言是一门很特殊的语言,Java程序需要进行编译步骤,但并不会生成特定平台的二进制机器码,它编译后生成的是一种与平台无关的字节码文件(*.class)(移植性好的原因),这种字节码自然不能被平台直接执行,运行时需要由解释器解释成相应平台的二进制机器码文件;大多数人认为Java是一种编译型语言,但我们说Java即是编译型语言,也是解释型语言也并没有错。

    二、解释型语言

    定义:指用专门解释器对源程序逐行解释成特定平台的机器码并立即执行的语言;相当于把编译型语言的编译链接过程混到一起同时完成的。

    解释型语言执行效率较低,且不能脱离解释器运行,但它的跨平台型比较容易,只需提供特定解释器即可。

    常见的解释型语言有, Python(同时是脚本语言)与Ruby等。

    三、脚本语言

    定义:为了缩短传统的编写-编译-链接-运行(edit-compile-link-run)过程而创建的计算机编程语言。

    特点:程序代码即是最终的执行文件,只是这个过程需要解释器的参与,所以说脚本语言与解释型语言有很大的联系。脚本语言通常是被解释执行的,而且程序是文本文件。

    典型的脚本语言有,JavaScript,Python,shell等。

    其他常用的脚本语句种类

    PHP是网页程序,也是脚本语言。是一款更专注于web页面开发(前端展示)的脚本语言,例如:Dedecms,discuz。PHP程序也可以处理系统日志,配置文件等,php也可以调用系统命令。

    Perl脚本语言。比shell脚本强大很多,语法灵活、复杂,实现方式很多,不易读,团队协作困难,但仍不失为很好的脚本语言,存世大量的程序软件。MHA高可用Perl写的

    Python,不但可以做脚本程序开发,也可以实现web程序以及软件的开发。近两年越来越多的公司都会要求会Python。

    Shell脚本与php/perl/python语言的区别和优势?

    shell脚本的优势在于处理操作系统底层的业务 (linux系统内部的应用都是shell脚本完成)因为有大量的linux系统命令为它做支撑。2000多个命令都是shell脚本编程的有力支撑,特别是grep、awk、sed等。例如:一键软件安装、优化、监控报警脚本,常规的业务应用,shell开发更简单快速,符合运维的简单、易用、高效原则.

      PHP、Python优势在于开发运维工具以及web界面的管理工具,web业务的开发等。处理一键软件安装、优化,报警脚本。常规业务的应用等php/python也是能够做到的。但是开发效率和复杂比用shell就差很多了。

    系统环境说明

    [root@clsn scripts]# cat /etc/redhat-release
    CentOS Linux release 7.4.1708 (Core)
    [root@clsn scripts]# uname -r
    3.10.0-693.el7.x86_64
    [root@clsn scripts]# getenforce
    Disabled
    [root@clsn scripts]# systemctl status firewalld.service
    ● firewalld.service - firewalld - dynamic firewall daemon
       Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)
       Active: inactive (dead)
         Docs: man:firewalld(1)

    1.1.5 系统中的shell

    查看系统中的命解释器

    [root@clsn ~]# cat /etc/shells
    /bin/sh
    /bin/bash
    /sbin/nologin
    /usr/bin/sh
    /usr/bin/bash
    /usr/sbin/nologin

    常用操作系统的默认shell

    1.Linux是Bourne Again shell(bash)

    2.Solaris和FreeBSD缺省的是Bourne shell(sh)

    3.AIX下是Korn Shell(ksh)

    4.HP-UX缺省的是POSIX shell(sh)

    [root@clsn ~]# echo $SHELL
    /bin/bash

    bash版本

    [root@clsn scripts]# bash -version

    GNU bash, 版本 4.2.46(2)-release (x86_64-redhat-linux-gnu) Copyright (C) 2011 Free Software Foundation, Inc. 许可证 GPLv3+: GNU GPL 许可证版本3或者更高 <http://gnu.org/licenses/gpl.html>

    这是自由软件,您可以自由地更改和重新发布。 在法律允许的范围内没有担保. 

    bash 破壳漏洞

    使用 命令 env x='() { :;}; echo be careful' bash -c "echo this is a test"
    如果返回结果为一行,则为正常,
    [root@clsn ~]# env x='() { :;}; echo be careful' bash -c "echo this is a test"
    this is a test

    #解决办法 升级当前的bash版本
    yum install update bash

    sh与bash 的关系

    [root@clsn ~]#  ll /bin/sh
    lrwxrwxrwx. 1 root root 4 11月 13 11:15 /bin/sh -> bash

    /bin与 /user/bin 的关系

    [root@clsn ~]# ll /bin -d
    lrwxrwxrwx. 1 root root 7 11月 13 11:15 /bin -> usr/bin

    1.2 脚本书写规范

    1.2.1 脚本统一存放目录

    [root@clsn ~]# mkdir -p /server/scripts/
    [root@clsn ~]# cd /server/scripts/

    1.2.2 选择解释器

    注意格式 ↓

    其中开头的"#!"字符又称为幻数,在执行bash脚本的时候,内核会根据"#!"后的解释器来确定该用那个程序解释这个脚本中的内容。

    [root@clsn scripts]# head -1 /etc/init.d/*
    ==> /etc/init.d/functions <==
    # -*-Shell-script-*-

    ==> /etc/init.d/netconsole <==
    #!/bin/bash

    ==> /etc/init.d/network <==
    #! /bin/bash

    1.2.3 编辑脚本使用vim

    使用 .vimrc 文件,能够快速的生成开头的注释信息

    [root@clsn scripts]# cat  ~/.vimrc
    autocmd BufNewFile *.py,*.cc,*.sh,*.java exec ":call SetTitle()"

    func SetTitle()
        if expand("%:e") == 'sh'
            call setline(1,"#!/bin/bash")
            call setline(2, "##############################################################")
            call setline(3, "# File Name: ".expand("%"))
            call setline(4, "# Version: V1.0")
            call setline(5, "# Author: clsn")
            call setline(6, "# Organization: http://blog.znix.top")
            call setline(7, "# Created Time : ".strftime("%F %T"))
            call setline(8, "# Description:")
            call setline(9, "##############################################################")
            call setline(10, "")
        endif
    endfunc

    使用后的效果

    [root@clsn scripts]# cat  scripts_test.sh
    #!/bin/bash
    ##############################################################
    # File Name: scripts_test.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-04 11:39:57
    # Description:  First scripts file
    ##############################################################

    在Shell脚本中,跟在#后面的内容表示注释。注释部分不会被执行,仅给人看。注释可以自成一行,也可以跟在命令后面,与命令同行。要养成写注释的习惯,方便自己与他人。

    最好不用中文注释,因为在不同字符集的系统会出现乱码。(字符集为zh_CN.UTF-8,为中文)。

    1.2.4 文件名规范

             名字要有意义,并且结尾以 .sh 结束

    1.2.5 开发的规范和习惯小结

    1) 放在统一的目录

    2) 脚本以.sh为扩展名

    3) 开头指定脚本解释器。

    4) 开头加版本版权等信息,可配置~/.vimrc文件自动添加。

    5) 脚本不要用中文注释,尽量用英文注释。

    6) 代码书写优秀习惯

      a、成对的内容一次性写出来,防止遗漏,如[  ]、' '、" "等

      b、[  ]两端要有空格,先输入[  ],退格,输入2个空格,再退格写。

      c、流程控制语句一次书写完,再添加内容。(if 条件 ; then  内容;fi)ddd

      d、通过缩进让代码易读。

      f、脚本中的引号都是英文状态下的引号,其他字符也是英文状态。

    1.3 shell脚本的执行

    1.3.1 执行脚本的办法

    sh/bash   scripts.sh
    chown +x   ./scripts.sh  && ./scripts.sh 
    source scripts.sh
    . (空格) scripts.sh
    cat oldboyedu.sh |bash  # 效率较低

    source 与 . (点) 的作用

    soucre命令

    [root@clsn ~]# help source  |head -2
    source: source 文件名 [参数]
        在当前 shell 中执行一个文件中的命令。

    . (点)

    [root@clsn scripts]# help . |head -2
    .: . 文件名 [参数]
        在当前 shell 中执行一个文件中的命令。

    1.3.2 sh 于 source的区别

     

    [root@clsn scripts]# sh  clsn_test.sh
    Hello World!
    [root@clsn scripts]# echo $clsn
    #  sh  新建一个Shell窗口(新建一个进程)执行一个文件中的命令。

    [root@clsn scripts]# source clsn_test.sh
    Hello World!
    [root@clsn scripts]# echo $clsn
    Hello World!

    面试题:

    问sh test.sh后echo $user返回的结果__空_ ?

    [root@oldboy scripts]# cat test.sh
    #!/bin/bash
    user=`whoami`

    1.4 Shell的变量

    1.4.1 什么是变量

    变量可以分为两类:环境变量(全局变量)和普通变量(局部变量)

      环境变量也可称为全局变量,可以在创建他们的Shell及其派生出来的任意子进程shell中使用,环境变量又可分为自定义环境变量和Bash内置的环境变量

      普通变量也可称为局部变量,只能在创建他们的Shell函数或Shell脚本中使用。普通变量一般是由开发者用户开发脚本程序时创建的。

             特殊变量

    1.4.2 环境变量

    使用 env/declare/set/export -p 命令查看系统中的环境变量,这三个命令的的输出方式稍有不同。

    [root@clsn scripts]# env
    XDG_SESSION_ID=1
    HOSTNAME=clsn
    TERM=linux
    SHELL=/bin/bash
    HISTSIZE=1000
    SSH_CLIENT=10.0.0.1 5537 22
    SSH_TTY=/dev/pts/0
    USER=root
    ~~~

             输出一个系统中的 环境变量

    [root@clsn ~]# echo $LANG
    zh_CN.UTF-8

    1.4.3 普通变量

    本地变量在用户当前的Shell生存期的脚本中使用。例如,本地变量OLDBOY取值为bingbing,这个值在用户当前Shell生存期中有意义。如果在Shell中启动另一个进程或退出,本地变量值将无效       

    定义普通变量实践

    [root@clsn ~]# a=1
    [root@clsn ~]# b='2'
    [root@clsn ~]# c="3"
    [root@clsn ~]# echo "$a"
    1
    [root@clsn ~]# echo "$b"
    2
    [root@clsn ~]# echo "${c}"

    提示:$变量名表示输出变量,可以用$c和${c}两种用法

    小结:连续普通字符串内容赋值给变量,不管用什么引号或者不用引号,它的内容是什么,打印变量就输出什么

    1.4.4 export命令

    [root@clsn ~]# help export
    export: export [-fn] [名称[=值] ...] 或 export -p
    为 shell 变量设定导出属性。

    标记每个 NAME 名称为自动导出到后续命令执行的环境。如果提供了 VALUE
    则导出前将 VALUE 作为赋值。

    export命令的说明

    当前shell窗口及子shell窗口生效

    在新开的shell窗口不会生效,生效需要写入配置文件

    # 定义变量

    [root@clsn scripts]# CSLN=clsn
    [root@clsn scripts]# export CSLN1=1

    # 当前窗口查看

    [root@clsn scripts]# echo $CSLN
    clsn
    [root@clsn scripts]# echo $CSLN1
    1

    # 编写测试脚本

    [root@clsn scripts]# vim quanju.sh
    #!/bin/bash
    echo $CSLN
    echo $CSLN1

    # 使用sh执行

    [root@clsn scripts]# sh  quanju.sh

    1

    # 使用source 执行

    [root@clsn scripts]# source quanju.sh
    clsn
    1

    1.4.5 环境变量相关配置文件

    /etc/proflie

    /etc/bashrc

    ~/.bashrc

    ~/.bash_profile

    /etc/proflie.d/  # 目录

    四文件读取顺序(CentOS6和7都一样)

    ① /etc/profile

    ② ~/.bash_profile

    ③ ~/.bashrc

    ④ /etc/bashrc

     

    文件读取过程示意图

    验证四文件读取顺序的方法

    sed -i '1a echo "$(date +%T-%s) /etc/profile1" >>/tmp/clsn' /etc/profile
    sed -i '$a echo "$(date +%T-%s) /etc/profile2" >>/tmp/clsn' /etc/profile
    sed -i '1a echo "$(date +%T-%s) /etc/bashrc1" >>/tmp/clsn' /etc/bashrc
    sed -i '$a echo "$(date +%T-%s) /etc/bashrc2" >>/tmp/clsn' /etc/bashrc
    sed -i '1a echo "$(date +%T-%s) ~/.bashrc1" >>/tmp/clsn' ~/.bashrc
    sed -i '$a echo "$(date +%T-%s) ~/.bashrc2" >>/tmp/clsn' ~/.bashrc
    sed -i '1a echo "$(date +%T-%s) ~/.bash_profile1" >>/tmp/clsn' ~/.bash_profile
    sed -i '$a echo "$(date +%T-%s) ~/.bash_profile2" >>/tmp/clsn' ~/.bash_profile

    1.4.6 环境变量的知识小结

    ü 变量名通常要大写。

    ü 变量可以在自身的Shell及子Shell中使用。

    ü 常用export来定义环境变量。

    ü 执行env默认可以显示所有的环境变量名称及对应的值。

    ü 输出时用“$变量名”,取消时用“unset变量名”。

    ü 书写crond定时任务时要注意,脚本要用到的环境变量最好先在所执行的Shell脚本中重新定义。

    ü 如果希望环境变量永久生效,则可以将其放在用户环境变量文件或全局环境变量文件里。

    1.4.7 变量中引号的使用

    只有在变量的值中有空格的时候,会使用引号。

    单引号与双引号的区别在于,是否能够解析特殊符号。

    [root@clsn ~]# name=znix
    [root@clsn ~]# name2='clsn'
    [root@clsn ~]# name3="http://blog.znix.top"
    [root@clsn ~]# echo $name
    znix
    [root@clsn ~]# echo $name2
    clsn
    [root@clsn ~]# echo $name3
    http://blog.znix.top
    [root@clsn ~]# name4='cl sn'
    [root@clsn ~]# echo $name4
    cl sn
    [root@clsn ~]# name5="cl sn"
    [root@clsn ~]# echo $name5
    cl sn
    [root@clsn ~]# name6='cl sn $PWD'
    [root@clsn ~]# echo $name6
    cl sn $PWD
    [root@clsn ~]# name6="cl sn $PWD"
    [root@clsn ~]# echo $name6
    cl sn /root

    1.4.8 普通变量的要求

    1)     内容是纯数字、简单的连续字符(内容中不带任何空格)时,定义时可以不加任何引号,例如:

    a.ClsnAge=22

    b.NETWORKING=yes

    2)     没有特殊情况时,字符串一律用双引号定义赋值,特别是多个字符串中间有空格时,例如:

    a.NFSD_MODULE="no load"

    b.MyName="Oldboy is a handsome boy."

    3)     当变量里的内容需要原样输出时,要用单引号(M),这样的需求极少,例如:

    a.OLDBOY_NAME='OLDBOY'

    变量使用反引号赋值

    [root@clsn scripts]# time=`date`
    [root@clsn scripts]# echo $time
    2017年 12月 05日 星期二 09:02:06 CST
       
    [root@clsn scripts]# file=`ls`
    [root@clsn scripts]# echo $file
    clsn_test.sh panduan.sh quanju.sh yhk.sh

    使用${}

    打印变量的时候防止出现“金庸新著”的问题

    [root@clsn scripts]# time=`date`
    [root@clsn scripts]# echo $time_day

    [root@clsn scripts]# echo ${time}_day
    2017年 12月 05日 星期二 09:02:06 CST_day
    [root@clsn scripts]# echo $time-day
    2017年 12月 05日 星期二 09:02:06 CST-day

    编写脚本测试${}

    # 使用脚本测试
    [root@clsn scripts]# vim bianliang.sh
    #!/bin/bash
    #############################################################
    # File Name: bianliang.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-05 09:10:29
    # Description:
    #############################################################
       
    time=`date`
    echo $timeday
    echo ${time}day
       
    [root@clsn scripts]# sh  bianliang.sh
       
    2017年 12月 05日 星期二 09:11:19 CSTday

    1.4.9 定义变量名技巧

    1. 变量名只能为字母、数字或下划线,只能以字母或下划线开头。

    2. 变量名的定义要有一定的规范,并且要见名知意。

    示例:

    ClsnAge=22       #<==每个单词的首字母大写的写法

    clsn_age=22      #<==单词之间用"_"的写法

    clsnAgeSex=man   #<==驼峰语法:首个单词的首字母小写,其余单词首字母大写

    CLSNAGE=22       #<==单词全大写的写法

    3. 一般的变量定义、赋值常用双引号;简单连续的字符串可以不加引号;希望原样输出时使用单引号。

    4. 希望变量的内容是命令的解析结果时,要用反引号'',或者用$()把命令括起来再赋值。

    1.5 特殊变量

    1.5.1 位置变量

    常用的特殊位置参数说明

    位置变量

    作用说明

    $0

    获取当前执行的shell脚本的文件名,如果执行脚本带路径那么就包括脚本路径。

    $n

    获取当前执行的shell脚本的第n个参数值,n=1..9,当n为0时表示脚本的文件名,如果n大于9用大括号括起来{10},参数以空格隔开。

    $#

    获取当前执行的shell脚本后面接的参数的总个数

    $*

    获取当前shell的所有传参的参数,不加引号同$@;如果给$*加上双引号,例如: “$*”,则表示将所有的参数视为单个字符串,相当于“1  2$3”。

    $@

    获取当前shell的所有传参的参数,不加引号同$*;如果给$@加上双引号,例如: “$@”,则表示将所有参数视为不同的独立字符串,相当于“$1” “$2” “$3” “……”,这是将参数传递给其他程序的最佳方式,因为他会保留所有内嵌在每个参数里的任何空白。

    当“$*”和“$@”都加双引号时,两者有区别,都不加双引号时,两者无区别。

    0,  1.$2 ~ 参数实践

    [root@clsn scripts]# vim chanshu.sh
    #!/bin/bash
    #############################################################
    # File Name: chanshu.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-05 09:39:16
    # Description:
    #############################################################
       
    echo $0
    echo "第一个参数:" $1
    echo "第二个参数:" $2
    echo "第11个参数:" ${11}
    [root@clsn scripts]# sh chanshu.sh
    chanshu.sh
    第一个参数:
    第二个参数:
    第11个参数:
    [root@clsn scripts]# sh chanshu.sh 1 2 3 4 5 6 7 8 9 10 11
    chanshu.sh
    第一个参数: 1
    第二个参数: 2
    第11个参数: 11

    $# 参数实践

    [root@clsn scripts]# vim chanshu.sh
    #############################################################
    # File Name: chanshu.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-05 09:39:16
    # Description:
    #############################################################


    echo $0
    echo "第一个参数:" $1
    echo "第二个参数:" $2
    echo "第10个参数:" ${10}
    echo "第11个参数:" ${11}
    echo "参数个数:" $#



    [root@clsn scripts]# sh chanshu.sh 55 2 3 4 5 6 7 8 9 10 11 112
    chanshu.sh
    第一个参数: 55
    第二个参数: 2
    第10个参数: 10
    第11个参数: 11
    参数个数: 12

    $* 参数实践

    [root@clsn scripts]# vim chanshu.sh
    #############################################################
    # File Name: chanshu.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-05 09:39:16
    # Description:
    #############################################################

    echo $0
    echo "第一个参数:" $1
    echo "第二个参数:" $2
    echo "第10个参数:" ${10}
    echo "第11个参数:" ${11}
    echo "参数个数:" $#
    echo "参数:" $*
    "chanshu.sh" 18L, 456C 已写入                                 
    [root@clsn scripts]# sh chanshu.sh 55 2 3 4 5 6 7 8 9 10 11 112
    chanshu.sh
    第一个参数: 55
    第二个参数: 2
    第10个参数: 10
    第11个参数: 11
    参数个数: 12
    参数: 55 2 3 4 5 6 7 8 9 10 11 112

    $* 与 $@ 对比实践

    [root@clsn scripts]# set -- "I am" handsome boy..
    [root@clsn scripts]# echo $1
    I am
    [root@clsn scripts]# echo $2
    handsome
    [root@clsn scripts]# echo $3
    boy..
    [root@clsn scripts]# echo $*
    I am handsome boy..
    [root@clsn scripts]# echo $@
    I am handsome boy..

    [root@clsn scripts]# for i in $*;do echo $i ;done
    I
    am
    handsome
    boy..
    [root@clsn scripts]# for i in $@;do echo $i ;done
    I
    am
    handsome
    boy..
    [root@clsn scripts]# for i in "$@";do echo $i ;done
    I am
    handsome
    boy..
    [root@clsn scripts]# for i in "$*";do echo $i ;done
    I am handsome boy..

    1.5.2 进程状态变量

    Shell进程的特殊状态变量说明

    参数

    参数说明

    -n

    不要追加换行

    -e

    启用下列反斜杠转义的解释

    -E

    显式地抑制对于反斜杠转义的解释

    `echo' 对下列反斜杠字符进行转义:

    \n

    换行

    \r

    回车

    \t

    横向制表符

    \b

    退格

    \v

    纵向制表符

    \c

    抑制更多的输出

    1.6 定义变量的方式

    1.6.1 三种定义变量的方式

      1、直接赋值

      2、传参 (传递参数)

      3、交互式设置变量,使用read命令

    1.6.2 read命令说明

    在命令行中使用

    [root@clsn scripts]# read
    132
    [root@clsn scripts]# echo $REPLY
    132
    [root@clsn scripts]# read clsn
    456
    [root@clsn scripts]# echo $clsn
    456
    [root@clsn scripts]# echo $REPLY
    132

    在脚本中使用

    [root@clsn scripts]# vim clsn_test.sh
    #!/bin/bash
    read -p '请输入:'  clsn

    echo $clsn

    执行结果

    [root@clsn scripts]# sh clsn_test.sh
    请输入:clsn_znix
    clsn_znix

    read命令的帮助说明

    [root@clsn scripts]# read --help
    -bash: read: --: 无效选项
    read: 用法:read [-ers] [-a 数组] [-d 分隔符] [-i 缓冲区文字] [-n 读取字符数] [-N 读取字符数] [-p 提示符] [-t 超时] [-u 文件描述符] [-s不显示终端的任何输入] [名称 ...]

    1.6.3 定义方法实践

    直接赋值方法

    [root@clsn scripts]# vim bianliang.sh
    # File Name: bianliang.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-05 09:10:29
    # Description:
    ##############################################################
    name=CLSN
    age=22
    sex=Man
    hobby=`ls`
    ethFile=/etc/sysconfig/network-scripts/ifcfg-eth0

    echo $hobby
    ls $ethFile
    [root@clsn scripts]# sh  bianliang.sh
    bianliang.sh chanshu.sh clsn.sh clsn_test.sh panduan.sh quanju.sh xiugaizhuji.sh yhk.sh
    /etc/sysconfig/network-scripts/ifcfg-eth0

    传参 (传递参数)

    [root@clsn scripts]# vim bianliang.sh
    ##############################################################
    # File Name: bianliang.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-05 09:10:29
    # Description:
    ##############################################################
    name=CLSN
    age=22
    sex=Man
    hobby=$1
    ethFile=$2

    echo $hobby
    ls $ethFile
    [root@clsn scripts]# sh  bianliang.sh  clsn /etc/hostname
    clsn
    /etc/hostname

    交互式设置变量 read

    [root@clsn scripts]# vim yhk.sh
    #!/bin/bash
    ##############################################################
    # File Name: yhk.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-04 17:01:44
    # Description:
    ##############################################################
    read -p  "请输入你的银行卡号:"  Yhk
    read -s -p  "请输入密码:" miMa
    echo
    echo "你的银行卡号:"  $Yhk
    echo "你的密码为:" $miMa
    # 测试结果
    [root@clsn scripts]# sh  yhk.sh
    请输入你的银行卡号:123456
    请输入密码:
    你的银行卡号: 123456
    你的密码为: 123456

    1.6.4 写一个交互脚本,实现能够定义主机名及IP地址

    脚本内容↓

    [root@clsn scripts]# cat xiugaizhuji.sh
    #!/bin/bash
    #############################################################
    # File Name: jiaohu.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-05 10:55:42
    # Description:
    #############################################################

    ethFile=/etc/sysconfig/network-scripts/ifcfg-eth[01]
    Now_eth=`hostname -I|awk -F "[. ]+" '{print $4}'`

    read -p "请输入主机名:" Hostname
    read -p "请输入IP地址的主机位:" HostIP

    hostnamectl set-hostname  $Hostname

    sed  -i "s#${Now_eth}#${HostIP}#g" $ethFile

    read -p "是否重启服务器:{yes/no}"  REboot

    if [ $REboot == yes ]
    then
       echo "系统将在10秒后重启!"
       shutdown -r  10
    else
       echo "请稍后手动重启系统!"
    fi

    脚本测试结果

    [root@clsn scripts]# sh xiugaizhuji.sh
    请输入主机名:clsn
    请输入IP地址的主机位:180
    是否重启服务器:{yes/no}yes
    系统将在10秒后重启!
    [root@clsn scripts]# sh xiugaizhuji.sh
    请输入主机名:clsn
    请输入IP地址的主机位:180
    是否重启服务器:{yes/no}no
    请稍后手动重启!

    1.7 变量的子串

    1.7.1 变量子串说明

    表达式

    说明

    ${parameter}

    返回变量$parameter的内容

    ${#parameter}

    返回变内容的长度(按字符),也适用于特殊变量

    ${parameterioffset}

    在变量${parameter}中,从位置offset之后开始提取子串到结尾

    ${parameter:offset:length}

    在变量${parameter}中,从位置offset之后开始提取长度为length的子串

    ${parameter#word}

    从变量${parameter}开头开始删除最短匹配的word子串

    ${parameter##word}

    从变量${parameter}开头开始删除最长匹配的word子串

    ${parameter%word}

    从变量${parameter}结尾开始删除最短匹配的word子串

    ${parameter%%word}

    从变量${parameter}结尾开始删除最长匹配的word子串

    ${parameter/pattem/string}

    使用string代替第一个匹配的pattern

    ${parameter//pattem/string}

    使用string代替所有匹配的pattern

    计算变赋值的长度

    [root@clsn scripts]# clsn=http://blog.znix.top
    [root@clsn scripts]# echo ${clsn} |wc -L
    20
    [root@clsn scripts]# echo ${#clsn}
    20
    [root@clsn scripts]# time echo ${clsn} |wc -L
    20

    real    0m0.002s
    user    0m0.002s
    sys    0m0.000s
    [root@clsn scripts]# time echo ${#clsn}
    20

    real    0m0.000s
    user    0m0.000s
    sys    0m0.000s

    截取变量中的字符

    [root@clsn scripts]# clsn=abcABC123ABCabc
    [root@clsn scripts]# echo ${clsn#abc}
    ABC123ABCabc
    [root@clsn scripts]# echo ${clsn##abc}
    ABC123ABCabc
    [root@clsn scripts]# echo ${clsn%abc}
    abcABC123ABC
    [root@clsn scripts]# echo ${clsn%%abc}
    abcABC123ABC
    [root@clsn scripts]# echo ${clsn#a*c}
    ABC123ABCabc
    [root@clsn scripts]# echo ${clsn##a*c}

    [root@clsn scripts]# echo ${clsn%a*c}
    abcABC123ABC
    [root@clsn scripts]# echo ${clsn%%a*c}

    [root@clsn scripts]# echo ${clsn#a*C}
    123ABCabc
    [root@clsn scripts]# echo ${clsn#a*C}
    123ABCabc
    [root@clsn scripts]# echo ${clsn##a*C}
    abc
    [root@clsn scripts]# echo ${clsn%a*c}
    abcABC123ABC
    [root@clsn scripts]# echo ${clsn%A*c}
    abcABC123
    [root@clsn scripts]# echo ${clsn%%A*c}
    abc

    替换变量内容

    [root@clsn scripts]# echo $clsn
    abcABC123ABCabc
    [root@clsn scripts]# echo ${clsn/abc/clsn}
    clsnABC123ABCabc
    [root@clsn scripts]# echo ${clsn//abc/clsn}
    clsnABC123ABCclsn

    有关上述匹配删除的小结

    #表示从幵头删除匹配最短。

    ##表示从开头删除匹配最长。

    %表示从结尾删除匹配最短。

    %%表示从结尾删除匹配最长。

    a*c表示匹配的突符串,*表示匹配所有,a*c匹配开头为a、中间为任意多个字符、结尾为c的字符串。

    a*C表示匹配的字符串,*表示匹配所有,a*C匹配开头为a、中间为任意多个字符、结尾为C的字符串。

    有关替换的小结

    一个“/”表示替换匹配的第-个字符串。

    两个“/”表示替换匹配的所有字符串。

    1.7.2 Shell的特殊扩展变量说明

    表达式

    说明

    ${parameter:-word}

    如果parameter的变量值为空或未赋值,则会返回word字符串并替代变量的值用途.如果变量未定义,则返回备用的值,防止变量为空值或因未定义而导致异常

    ${parameter:=word}

    如果parameter的变量值为空或未赋值,则设置这个变量值为word,并返回其值。位置变量和特殊变量不适用用途:基本同上一个${parameter>word},但该变量又额外给parameter变量赋值了

    ${parameter:?word}

    如果parameter变量值为空或未赋值,那么word字符串将被作为标准错误输出,否则输出变量的值。用途:用于捕捉由于变量未定义而导致的错误,并退出程序

    ${parameter:+word}

    如果parameter变量值为空或未赋值,则什么都不做,否则word字符串将替代变量的值

    特殊变量实践

    脚本内容

    [root@clsn scripts]# cat  clsn.sh
    #!/bin/bash
    #############################################################
    # File Name: clsn.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-05 12:13:38
    # Description:
    #############################################################
    dir=
    echo ${dir:-/tmp}
    echo ${dir}
    echo ${dir:=/mnt}
    echo ${dir}
    dir2= (空格)
    echo ${dir2-/tmp}
    echo ${dir2}
    echo ${dir2:-/tmp}
    echo ${dir2}
    echo ${dir2=/mnt}
    echo ${dir2}

    测试结果

    [root@clsn scripts]# sh clsn.sh
    /tmp

    /mnt
    /mnt


    /tmp

    至此shell中的变量就都介绍完了

    1.8 变量的数值计算

    1.8.1 仅支持整数的运算

    echo $((数学运算表达式))

    # 形式一
    [root@clsn scripts]# echo $((1 + 1))
    2
    [root@clsn scripts]# echo $((2*7-3/6+5))
    19
    # 形式二
    [root@clsn scripts]# ((clsn=2*8))
    [root@clsn scripts]# echo $clsn
    16
    # 形式三
    [root@clsn scripts]# znix=$((2*7-3/6+5))
    [root@clsn scripts]# echo $znix
    19

    延伸产物(重要)

    i++ 自增1

    i-- 自减1

    ++i

    --i

             示例:

    [root@clsn scripts]# i=1
    [root@clsn scripts]# echo $((i++))
    1
    [root@clsn scripts]# echo $((i++))
    2
    [root@clsn scripts]# echo $((i--))
    3
    [root@clsn scripts]# echo $((i--))
    2
    [root@clsn scripts]# echo $((i--))
    1
    [root@clsn scripts]# echo $((++i))
    1
    [root@clsn scripts]# echo $((++i))
    2
    [root@clsn scripts]# echo $((++i))
    3
    [root@clsn scripts]# echo $((--i))
    2
    [root@clsn scripts]# echo $((--i))
    1
    [root@clsn scripts]# echo $((--i))
    0

    记忆方法:++,--

    变量a在前,表达式的值为a,然后a自增或自减,变量a在符号后,表达式值自增或自减,然后a值自增或自减。

    let命令

    [root@clsn scripts]# i=1
    [root@clsn scripts]# i=i+1
    [root@clsn scripts]# echo $i
    i+1

    [root@clsn scripts]# i=1
    [root@clsn scripts]# let i=i+1
    [root@clsn scripts]# echo $i
    2

    expr 命令

    1.整数计算

    2.判断扩展名

    3.判断输入是否为整数,非整数返回值为2

    4.计算变量的长度

    [root@clsn scripts]# expr 1+1
    1+1
    [root@clsn scripts]# expr 1 + 1
    2
    [root@clsn scripts]# expr 1 * 1
    expr: 语法错误
    [root@clsn scripts]# expr 1 \* 1
    1

    非整数返回值为2 示例:

    [root@clsn scripts]# expr 1 + 1
    2
    [root@clsn scripts]# echo $?
    0
    [root@clsn scripts]# expr -1 + 1
    0
    [root@clsn scripts]# echo $?
    1
    [root@clsn scripts]# expr a + 1
    expr: 非整数参数
    [root@clsn scripts]# echo $?
    2

    $[]运算符

    [root@clsn scripts]# echo $[1+2]
    3
    [root@clsn scripts]# echo $[1-2]
    -1
    [root@clsn scripts]# echo $[1*2]
    2
    [root@clsn scripts]# echo $[1/2]
    0

    [root@clsn scripts]# typeset -i A=2017 B=2018
    [root@clsn scripts]# A=A+B
    [root@clsn scripts]# echo $A
    4035

    1.8.2 可以进行小数运算的命令

    bc    命令

    # 安装 bc  依赖于base源
    [root@clsn scripts]# yum -y install bc

      交互模式测试bc命令

    [root@clsn scripts]# bc
    bc 1.06.95
    Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
    1+1
    2
    [root@clsn scripts]# echo 1+1.1|bc
    2.1

    免交互模式测试bc命令

    [root@clsn scripts]# echo 'scale=6;1/3'|bc
    .333333

    python 命令

    [root@clsn scripts]#  file `which yum `
    /usr/bin/yum: Python script, ASCII text executable
    [root@clsn scripts]# python
    >>> import os
    >>> os.system('df -h')
    >>> 1+1.1
    2.1
    >>>exit()

    awk 命令

    [root@clsn ~]# echo "7.7 3.8"|awk '{print ($1-$2)}'
    3.9
    [root@clsn ~]# echo "358 113"|awk '{print ($1-3)/$2}'
    3.14159
    [root@clsn ~]# echo "3 9"|awk '{print ($1+3)*$2}'
    54
    [root@backup scripts]# awk BEGIN'{print 1.2+3.3}'
    4.5

    1.8.3 运算相关练习题

    1.8.3.1 【练习题】实现一个加减乘除等功能的计算器

    实现脚本:

    [root@clsn scripts]# cat jishuanqi.sh
    #!/bin/bash
    #############################################################
    # File Name: jishuanqi.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-06 08:57:13
    # Description:
    #############################################################

    read -p "请输入第一个整数:" a
    read -p "请输入第二个整数:" b


    echo $a + $b =$(($a+$b))
    echo $a - $b =$(($a-$b))
    echo $a \* $b =$(($a*$b))
    echo $a / $b =$(($a/$b))

             脚本执行过程:

    [root@clsn scripts]# sh jishuanqi.sh
    请输入第一个整数:12
    请输入第二个整数:12
    12 + 12 =24
    12 - 12 =0
    12 * 12 =144
    12 / 12 =1

    精简方法

    [root@clsn scripts]# vim jishuanqi2.sh
    #!/bin/bash
    #############################################################
    # File Name: jishuanqi2.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-06 15:02:41
    # Description:
    #############################################################
    echo $(($1))

             脚本执行过程:

    [root@clsn scripts]# sh jishuanqi2.sh  1+1
    2
    [root@clsn scripts]# sh jishuanqi2.sh  1*9
    9

    1.8.3.2 【练习题】打印结果1+2+3+4+5+6+7+8+9+10=55

    脚本内容

    [root@clsn scripts]# vim yunshuan.sh
    #!/bin/bash
    #############################################################
    # File Name: yunshuan.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-06 09:40:31
    # Description:
    #############################################################

    Num=`seq -s + 1 10`
    echo  $Num=$(($Num))

    脚本执行结果

    [root@clsn scripts]# sh  yunshuan.sh
    1+2+3+4+5+6+7+8+9+10=55

    1.9 补充说明

    shell脚本中批量注释的方法

    <<'EOF'
    文件内容
    EOF
       或
       使用 exit可以注释其之后的所有内容(类似注释,实质为不执行后面的内容)

     

    Shell编程基础篇-下

    2.1 条件表达式

    2.1.1 文件判断

    常用文件测试操作符

    常用文件测试操作符

    说明

    -d文件,d的全拼为directory

    文件存在且为目录则为真,即测试表达式成立

    -f文件,f的全拼为file

    文件存在且为普通文件则为真,即测试表达式成立

    -e文件,e的全拼为exist

    文件存在则为真,即测试表达式成立。注意区别于“-f”,-e不辨别是目录还是文件

    -r文件,r的全拼为read

    文件存在且可读则为真,即测试表达式成立

    -s文件,s的全拼为size

    文件存在且文件大小不为0则为真,即测试表达式成立

    -w文件,w的全拼为write

    文件存在且可写则为真,即测试表达式成立

    -x文件,x的全拼为executable   

    文件存在且可执行则为真,即测试表达式成立

    -L文件,L的全拼为link

    文件存在且为链接文件则为真,即测试表达式成立

    fl -nt f2,nt 的全拼为 newer than

    文件fl比文件f2新则为真,即测试表达式成立。根据文件的修改时间来计算

    fl -ot f2,ot 的全拼为 older than

    文件fl比文件f2旧则为真,即测试表达式成立。根据文件的修改时间来计算

    判断文件是否存在

    [root@clsn scripts]# [ -f /etc/hosts ]
    [root@clsn scripts]# echo $?
    0
    [root@clsn scripts]# [ -f /etc/hosts1 ]
    [root@clsn scripts]# echo $?
    1

    判断文件是否存在,返回方式

    [root@clsn scripts]# [ -f /etc/hosts ] && echo "文件存在" || echo "文件不存在"
    文件存在
    [root@clsn scripts]# [ -f /etc/hosts1 ] && echo "文件存在" || echo "文件不存在"
    文件不存在

    判断目录是否存在

    [root@clsn scripts]# [ -d /tmp ] && echo "目录存在" || echo "目录不存在"
    目录存在
    [root@clsn scripts]# [ -d /tmp1 ] && echo "目录存在" || echo "目录不存在"
    目录不存在

    使用变量的方法进行判断

    dir=/etc1/;[ -d $dir ] && tar zcf etc.tar.gz $dir || echo "$dir目录不存在"

    2.1.2 字符串判断

    字符串测试操作符 

    常用字符串测试操作符

    说明

    -n "字符串"

    若字符串的长度不为0,则为真,即测试表达式成立,n可以理解为no zero

    -Z "字符串"

    若字符串的长度为0,则为真,即测试表达式成立,z可以理解为zero的缩写

    "串 1"== "串 2"

    若字符串1等于字符串2,则为真,即测试表达式成立,可使用"=="代替"="

    "串 1" != "串 2"        

    若字符串1不等于字符串2,则为真,即测试表达式成立,但不能用"!=="代替"!="

    1.对于字符串的测试,一定要将字符串加双引号之后再进行比较。

    2.空格非空

    -z 判断字符串长度

    [root@clsn scripts]# x=  ; [ -z "$x" ] && echo "输入为空" || echo '输入有内容'
    输入为空
    [root@clsn scripts]# x=12 ; [ -z "$x" ] && echo "输入为空" || echo '输入有内容'
    输入有内容

    -n 判断字符串长度

    [root@clsn scripts]# x=12 ; [ -n "$x" ] && echo "输入有内容" || echo '输入为空'
    输入有内容
    [root@clsn scripts]# x= ; [ -n "$x" ] && echo "输入有内容" || echo '输入为空'
    输入为空

    "串 1" == " 串 2 "       使用定义变量的方式进行判断

    cmd=$1
    [ "$cmd" == "start" ] && echo start
    # 测试
    [root@clsn scripts]# cmd=start;[ "$cmd" == "start" ] && echo start
    start

    2.1.3 整数判断

    整数二元比较操作符参考

    在[]以及test中

    使用的比较符号

    在(())和[[]]中

    使用的比较符号

    说明

    -eq

    ==或=

    相等,全拼为equal

    -ne

    !=

    不相等,全拼为not equal

    -gt

    大于,全拼为greater than

    -ge

    >=

    大于等于,全拼为greater equal

    -lt

    小于,全拼为丨ess than

    -le

    <=

    小于等于,全拼为less equal

    判断两数是否相等

    [root@clsn scripts]# [ 1 -eq 1 ]
    [root@clsn scripts]# echo $?
    0
    [root@clsn scripts]# [ 1 -eq 2 ]
    [root@clsn scripts]# echo $?
    1

    大于等于

    [root@clsn ~]# [ 11 -ge 1 ] && echo "成立" || echo "不成立"
    成立

    小于

    [root@clsn ~]# [ 11 -lt 1 ] && echo "成立" || echo "不成立"
    不成立

    大于

    [root@clsn ~]# [ 11 -gt 1 ] && echo "成立" || echo "不成立"
    成立

    不等于

    [root@clsn ~]# [ 11 -ne 1 ] && echo "成立" || echo "不成立"
    成立

    2.1.4 逻辑符号

    常用逻辑操作符 

    在[]和test中使用的操作符

    说明

    在[[]]和中使用的操作符

    说明

    -a

    [ 条件A -a  条件B ]

    A与B都要成立,整个表达式才成立

    &&

    and,与,两端都为真,则结果为真

    -o

    [ 条件A -o  条件B]

    A与B都不成立,整个表达式才不成立

    ||

    or,或,两端有一个为真,则结果为真

     

    !

    not,非,两端相反,则结果为真

    逻辑操作符与整数判断配合

    [root@clsn ~]# [ 11 -ne 1 ] && echo "成立" || echo "不成立"
    成立

     取反

    [root@clsn ~]# [ ! 11 -ne 1 ] && echo "成立" || echo "不成立"
    不成立

    两边都为真

    [root@clsn ~]# [  11 -ne 1 -a 1 -eq 1 ] && echo "成立" || echo "不成立"
    成立

    至少有一边为真

    [root@clsn ~]# [  11 -ne 1 -o 1 -eq 1 ] && echo "成立" || echo "不成立"
    成立

    感叹号的特殊用法

             使用历史命令,感叹号加上history中的序号,即可执行

    [root@clsn ~]#  !516
    ls
    anaconda-ks.cfg  bootime.avg  setup.sh  vim

    2.1.5 【练习题】开发3个shell脚本比较2个整数大小

    要求:

    1. 分别以定义变量,脚本传参以及read读入的方式写3个脚本。

    2. 用条件表达式(禁止if语句)进行判断。

    3. 将2个整数的比较结果输出到屏幕,出错需要提示。

    使用定义变量方法

    [root@clsn panduan1]# cat panduan1.sh
    #!/bin/bash
    #############################################################
    # File Name: panduan1.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-06 11:27:32
    # Description:
    #############################################################

    NUM1=6
    NUM2=2

    expr 1 + $NUM1  &>/dev/null
    [ $? -eq 2 ] && echo "$NUM1 不是整数 " &&  exit 2
    expr 1 + $NUM2 &>/dev/null
    [ $? -eq 2 ] && echo "$NUM2 不是整数 " &&  exit 2

    [ "$NUM1" -eq "$NUM2" ] && echo $NUM1 = $NUM2  && exit
    [ "$NUM1" -gt "$NUM2" ] && echo $NUM1 \> $NUM2 && exit
    [ "$NUM1" -lt "$NUM2" ] && echo $NUM1 \< $NUM2

    使用传参方法

    [root@clsn panduan1]# cat panduan_chuanchan.sh
    #!/bin/bash
    #############################################################
    # File Name: panduan1.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-06 11:27:32
    # Description:
    #############################################################
    [ $# -ne 2 ] && echo "UASGE $0 num1 num2 " && exit

    NUM1=$1
    NUM2=$2

    expr 1 + $NUM1  &>/dev/null
    [ $? -eq 2 ] && echo "$NUM1 不是整数 " &&  exit 2
    expr 1 + $NUM2  &>/dev/null
    [ $? -eq 2 ] && echo "$NUM2 不是整数 " &&  exit 2

    [ "$NUM1" -eq "$NUM2" ] && echo $NUM1 = $NUM2  && exit
    [ "$NUM1" -gt "$NUM2" ] && echo $NUM1 \> $NUM2 && exit
    [ "$NUM1" -lt "$NUM2" ] && echo $NUM1 \< $NUM2

    使用read读入

    [root@clsn panduan1]# cat panduan_read.sh
    #!/bin/bash
    #############################################################
    # File Name: panduan1.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-06 11:27:32
    # Description:
    #############################################################

    read -p "请输入第一个整数:" NUM1
    read -p "请输入第二个整数:" NUM2

    expr 1 + $NUM1  &>/dev/null
    [ $? -eq 2 ] && echo "$NUM1 不是整数 " &&  exit 2
    expr 1 + $NUM2  &>/dev/null
    [ $? -eq 2 ] && echo "$NUM2 不是整数 " &&  exit 2

    [ "$NUM1" -eq "$NUM2" ] && echo "$NUM1 = $NUM2"  && exit
    [ "$NUM1" -gt "$NUM2" ] && echo "$NUM1 > $NUM2" && exit
    echo "$NUM1 < $NUM2"

    2.2 if条件语句

      # 条件表达式和if语句可以互相转换

    2.2.1 三种语法

    单分支语句

    if [ -f /etc/hosts ]

    then

        echo '文件存在'

    fi

    双分支语句

    if [ -f /etc/hosts ] 

    then

       echo "文件存在"

    else

    echo "文件不存在"

       echo "..." >>/tmp/test.log

    fi

    多分支语句

    if [ -f /etc/hosts ] 

    then

       echo " hosts文件存在"

    elif [ -f /etc/host ]

    then

       echo " host文件存在"

    fi

    2.2.2 if条件语句小结

      单分支:一个条件一个结果

      双分支:一个条件两个结果

      多分支:多个条件多个结果

    2.2.3 【练习题1】输入2个数字,比较大小(使用if语句结合条件表达式实现) 

    说明:

    3个脚本:使用直接赋值,传参,read任一种方法写3种脚本(单分支,双分支,多分支)

    示例脚本一:

    read方法 单分支

    1 [root@clsn panduan1]# cat if_panduan_1.sh
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: panduan1.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-06 11:27:32
    9 # Description:
    10 #############################################################
    11
    12 read -p "请输入第一个整数:" NUM1
    13 expr 1 + $NUM1  &>/dev/null
    14     if [ $? -eq 2 ]
    15       then
    16         echo "$NUM1 不是整数 "
    17         exit 2
    18     fi
    19
    20 read -p "请输入第二个整数:" NUM2
    21 expr 1 + $NUM2  &>/dev/null
    22     if [ $? -eq 2 ]
    23       then
    24          echo "$NUM2 不是整数 "
    25          exit 2
    26     fi
    27
    28 # 判断输入数值大小
    29     if [ $NUM1 -eq $NUM2 ]
    30       then
    31         echo "$NUM1 = $NUM2"
    32         exit
    33     fi
    34  
    35     if [ $NUM1 -gt $NUM2 ]
    36       then
    37         echo "$NUM1 > $NUM2"
    38         exit
    39     fi
    40   
    41     if [ $NUM1 -lt $NUM2 ]
    42       then
    43         echo "$NUM1 < $NUM2"
    44     fi

    示例脚本二:

    双分支

    1 [root@clsn panduan1]# cat if_panduan_2.sh
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: if_panduan_2.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-06 11:27:32
    9 # Description:
    10 #############################################################
    11
    12 read -p "请输入第一个整数:" NUM1
    13   expr 1 + $NUM1  &>/dev/null
    14       if [ $? -eq 2 ]
    15         then
    16           echo "$NUM1 不是整数 "
    17           exit 2
    18       fi
    19
    20 read -p "请输入第二个整数:" NUM2
    21   expr 1 + $NUM2  &>/dev/null
    22       if [ $? -eq 2 ]
    23         then
    24            echo "$NUM2 不是整数 "
    25            exit 2
    26       fi
    27
    28 # 判断输入数值大小
    29     if [ $NUM1 -eq $NUM2 ]
    30       then
    31         echo "$NUM1 = $NUM2"
    32         exit
    33     else
    34         if [ $NUM1 -gt $NUM2 ]
    35           then
    36             echo "$NUM1 > $NUM2"
    37             exit
    38         else
    39             if [ $NUM1 -lt $NUM2 ]
    40               then
    41               echo "$NUM1 < $NUM2"
    42             fi
    43         fi
    44     fi

    示例脚本三:

    多分支

    1 [root@clsn panduan1]# cat if_panduan_3.sh
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: if_panduan_3.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-06 11:27:32
    9 # Description:
    10 #############################################################
    11
    12 read -p "请输入第一个整数:" NUM1
    13   expr 1 + $NUM1  &>/dev/null
    14    NUM1_FH=$?  
    15       if [ $NUM1_FH -eq 2 ]
    16         then
    17           echo "$NUM1 不是整数 "
    18           exit 2
    19       else 
    20         read -p "请输入第二个整数:" NUM2
    21         expr 1 + $NUM2  &>/dev/null
    22         NUM2_FH=$?
    23         if [ $NUM2_FH -eq 2 ]
    24          then
    25            echo "$NUM2 不是整数 "
    26            exit 2
    27         fi
    28       fi
    29
    30 # 判断输入数值大小
    31     if [ $NUM1 -eq $NUM2 ]
    32       then
    33         echo "$NUM1 = $NUM2"
    34         exit
    35     elif [ $NUM1 -gt $NUM2 ]
    36       then
    37         echo "$NUM1 > $NUM2"
    38         exit
    39     elif [ $NUM1 -lt $NUM2 ]
    40       then
    41         echo "$NUM1 < $NUM2"
    42     fi

    2.2.4 【练习题2】系统内存低于100M邮件报警,加入计划任务,3分钟检查一次。

    对于开发程序而言,一般来说应该遵循下面的3步法则。

    (1)分析需求

        明白开发需求,是完成程序的大前提,因此,分析需求至关重要,一切不以需求为主的程序开发,都是耍流氓的!

    (2)设计思路

    设计思路就是根据需求,把需求进行拆解,分模块逐步实现,例如本题可以分为如下几步:

    1)获取当前系统剩余内存的值(先在命令行实现)。

    2)配置邮件报警(可采用第三方邮件服务器)。

    3)判断取到的值是否小于100MB,如果小于100MB,就报警(采用if语句)。

    4)编码实现Shell脚本。

    5)加入crond定时任务,每三分钟检查一次。

    (3)编码实现

        编码实现就是具体的编码及调试过程,工作中很可能需要先在测试环境下调试,调试好了,再发布到生产环境中。

    第一步 先配置邮件服务,保证能够发生邮件

    echo 'set from=mail@znix.top smtp=smtp.znix.top smtp-auth-user=mail@znix.top  smtp-auth-password=****** smtp-auth=login' >> /etc/mail.rc

    发送测试邮件发送

    echo "`date +%F_%T`" |mail -s "这是测试邮件" admin@znix.top

     

     

    第二步编写检查脚本

    [root@clsn scripts]# cat mem_info.sh
    #!/bin/bash
    ##############################################################
    # File Name: mem_info.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-06 8:42:50
    # Description:
    ##############################################################

    Mem=`free -m |awk 'NR==2{print $NF}'`
    host=`hostname`
    Ip=`hostname -I`
    Date=`date +%F_%T`
    mail_file=/tmp/mail.s
    dest_user=admin@znix.top

    if [ $Mem -lt 100 ]
    then
       echo "发生时间: $Date" >$mail_file
       echo "发生主机: $host  主机IP地址: $Ip " >> $mail_file
       echo "内存余量: $Mem M" >> $mail_file
       mail -s "【警告】内存不足了呀!"  $dest_user < $mail_file
    fi

    第三步测试脚本(可以修改判断的值)

    [root@clsn scripts]# sh mem_info.sh

     

     

    第四步 脚本测试成功,写入定时任务

    [root@clsn panduan1]# crontab -l
    # 检查内存剩余大小
    */3 * * * * /bin/sh /server/scripts/panduan/mem_info.sh  &>/dev/null

    至此,一个监控脚本就写好了

    2.2.5 【练习题3】模拟编写启动nginx脚本

    脚本内容

    nginx 启动脚本

    1 [root@clsn scripts]# cat nginx.sh
    2 #!/bin/bash
    3 ##############################################################
    4 # File Name: nginx.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-05 20:56:06
    9 # Description:
    10 ##############################################################
    11 . /etc/init.d/functions 
    12
    13 StartCheck=`netstat -lntup  |grep -c 80`
    14 StartCMD='/application/nginx/sbin/nginx '
    15 StopCMD='/application/nginx/sbin/nginx -s stop '
    16 StatusCheck=`netstat -lntp|grep -c nginx`
    17 ReloadCMD='/application/nginx/sbin/nginx -s reload'
    18 CheckCMD='/application/nginx/sbin/nginx  -t'
    19 UsaGe="Usage: $0 {start|stop|status|reload|check}"
    20
    21
    22 COMMAND=$1
    23
    24 if [  $# -ne 1 ]
    25   then
    26     echo $UsaGe  && exit 2
    27 fi
    28
    29 if [ $COMMAND = start ]
    30  then
    31     if [ $StartCheck  == 1  ]
    32       then
    33       action  "启动Nginx失败,端口被占用"  /bin/false
    34     else
    35       $StartCMD
    36       action  "启动Nginx"  /bin/true
    37     fi
    38 elif [ $COMMAND = stop ]
    39   then
    40       $StopCMD  &>/dev/null
    41       if [ $? -eq 0 ]
    42         then
    43           action   "停止Nginx"   /bin/true
    44       else
    45           action   "停止Nginx"   /bin/false
    46       fi
    47 elif [ $COMMAND = status ]
    48   then
    49     if [ $StatusCheck -eq 1 ]
    50       then
    51         echo "nginx 正在运行..."
    52     else
    53         echo "Nginx 未运行."
    54     fi
    55 elif [ $COMMAND = reload ]
    56   then
    57     $ReloadCMD
    58     action  "reload" /bin/true
    59 elif [ $COMMAND = check ]
    60   then
    61     $CheckCMD
    62 else
    63  echo $UsaGe
    64  exit 2
    65 fi

    脚本执行过程: 

     

    2.2.6 【练习题5】Web及MySQL服务异常监测案例

    用if条件语句实现对Nginx Web服务以及MySQL数据库服务是否正常进行检测,如果服务未启动,则启动相应服务。

    脚本编写思路:

    判断web服务器正常 ↓

      1、进程 ps -ef |grep [n]ginx
      2、端口  netstat  ss losf telnet  nc  nmap
      3、curl 页面 返回值
      4、curl check.html 的内容

    判断mysql服务器正常 ↓

        1、端口 netstat  ss losf telnet  nc  nmap
        2、进程 ps -ef |grep [m]ysql
        3、mysql 登录访问看一下
        4、mysql insert一个数据 select一个数据

    web服务监控脚本示例

    web 监控脚本内容

    1 [root@clsn scripts]# cat  web_check.sh
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: web_check.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-07 10:53:38
    9 # Description:
    10 #############################################################
    11 . /etc/init.d/functions
    12
    13 JinChen=`ps -ef |grep -c  [n]ginx`
    14 QiDong='/server/scripts/nginx.sh start'
    15 StatuS=`curl -I -w "%{http_code}\n" -o /dev/null -s   10.0.0.180`
    16 StatuS2=`curl -s 10.0.0.180/check.html|grep -c ok`
    17 StartNginx='/server/scripts/nginx.sh start'
    18
    19 if [ $JinChen -ge 2  ]
    20   then
    21     if [ "$StatuS" -eq 200 ]
    22       then
    23         if [ "$StatuS2" -eq 1 ]
    24           then
    25             action "Nginx 服务运行正常" /bin/true
    26           else
    27             action "请检查chenk.html文件!" /bin/false
    28         fi
    29     else
    30       action "请检查首页文件!" /bin/false
    31     fi
    32 else
    33     action "Nginx 未正常运行!" /bin/false
    34     $StartNginx   
    35 fi

    脚本执行过程:

     

    2.3 case条件结构语句

    2.3.1 case语法结构

    case "字符串变量" in
      值1)
         指令1
         ;;
      值2)
         指令2
         ;;
      值*)
         指令
    esac

    2.3.2 case与if的对比

    case书写方式

    case $name in
      值1)
          指令1
          ;;
      值2)
          指令2
          ;;
       *)
          指令
    esac

    if书写方式

    if [ $name == "值1" ]
      then
        指令1
    elif [ $name == "值2" ]
      then
        指令2
    else
        指令   
    fi

    2.3.3 case值的书写方式

    apple)

          echo -e "$RED_COLOR apple $RES"

          ;;

    也可以这样写,输入2种格式找同一个选项

    apple|APPLE)

          echo -e "$RED_COLOR apple $RES"

          ;;

    2.3.4 case语句小结

        ? case语句就相当于多分支的if语句。case语句的优势是更规范、易读。

        ? case语句适合变量的值少,且为固定的数字或字符串集合。(1,2,3)或(start,stop,restart)。

          ? 系统服务启动脚本传参的判断多用case语句,多参考rpcbind/nfs/crond脚本;菜单脚本也可以使用case

    2.3.5 【练习题1】使用case编写一个菜单脚本

    脚本内容

    菜单脚本内容

    1 [root@clsn case]# cat menu.sh
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: menu.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-07 14:47:36
    9 # Description:
    10 #############################################################
    11
    12
    13 cat<<EOF
    14 1. install rsync
    15 2. install nfs
    16 3. install mysql
    17 4. install all
    18 EOF
    19
    20 read -p '请输入你的选择:' chs
    21
    22 case $chs in
    23   1)
    24    echo install rsync success
    25    ;;
    26   2)
    27    echo install nfs success
    28    ;;
    29   3)
    30    echo install mysql success
    31    ;;
    32   4)
    33    echo install rsync/nfs/mysql success
    34    ;;
    35   *)
    36    echo "你输入有误"
    37 esac

     

    脚本执行过程:

     

    2.3.6 【练习题2】输出带有颜色的水果菜单

    脚本内容:

    水果菜单脚本

    1 [root@clsn scripts]# cat fruits.sh
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: fruits.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-06 21:23:31
    9 # Description:
    10 #############################################################
    11 cat <<EOF
    12 =======================
    13 1.apple
    14 2.pear
    15 3.banana
    16 4.exit
    17 =======================
    18 EOF
    19 read -t 10 -p  "你要看什么水果:" Menu_Num
    20
    21 case "$Menu_Num" in
    22   1)
    23    echo -e "\033[31m apple \033[0m"
    24    ;;
    25   2)
    26    echo -e "\033[32m pear \033[0m"
    27    ;;
    28   3)
    29    echo -e "\033[33m banana \033[0m"
    30    ;;
    31   4)
    32    exit
    33 esac

     

    脚本执行过程:

     

    2.3.7 写脚本规范及注意事项

      1.变量名称不能和系统已经存在的命令等重复  free  == > Free

      2. 判断单位要统一

      3. 脚本一行不超过一屏的一半。

      4. 能写成变量的内容尽量写成变量

    2.4 练习题

    2.4.1 【练习题1】监控Memcached缓存服务是否正常

      监控Memcached缓存服务是否正常,模拟用户(web客户端)检测。

      使用nc命令加上set/get来模拟检测。

        memecached安装:http://www.cnblogs.com/clsn/p/7999510.html

    脚本内容:

    监控 memcached脚本

    1 [root@clsn scripts]# vim  memcache_check.sh
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: memcache_check.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-07 15:50:03
    9 # Description:
    10 #############################################################
    11 . /etc/init.d/functions
    12 . /etc/init.d/run  # 函数 jingdutiao 使用
    13 MemPort=`netstat -lntp  |grep -c  0.0.0.0:11211`
    14 Set_Key='printf "set clsn2017 0 10 8\r\nclsn2018\r\n"|nc 10.0.0.180 11211'
    15 Get_Key='printf "get clsn2017\r\n" |nc 10.0.0.180 11211 |grep -c clsn2018'
    16 ReStart='systemctl restart memcached.service'
    17
    18 if [ $MemPort -eq 1 ]
    19   then
    20     $Set_Key
    21     $Get_Key
    22     if [ $? -ne 1 ]
    23       then
    24       action "Memcached 运行正常!" /bin/true
    25     else
    26       action "Memcached 服务异常!"  /bin/false
    27     fi
    28 else
    29     action "服务未启动!" /bin/false
    30     $ReStart
    31     jingdutiao
    32 fi

    脚本执行过程

     

    2.4.2 【练习题2】使用(case)编写rsync管理脚本

    写网络服务独立进程模式下Rsync的系统启动脚本,例如:/etc/init.d/rsyncd {start|stop|restart}。

    要求:

      1.要使用系统函数库技巧。

      2.要用函数,不能一坨?的方式。

      3.在centos 6中 可被chkconfig管理。

    注意:

      服务的停止操作和启动操作之间要有间隔时间,使用sleep 1                   

    pkill 进程

    sleep 1

    start 服务

    rsync服务启动脚本

    1 [root@clsn scripts]# cat rsyncd
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: rsync_admin.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-07 18:39:37
    9 # Description:
    10 #############################################################
    11
    12 . /etc/init.d/functions
    13 . /etc/init.d/run
    14
    15 Rsync_Port=`netstat -lntup |grep -c  0.0.0.0:873`
    16 Rsync_COM1='rsync --daemon'
    17 Rsync_COM2='pkill rsync'
    18
    19 Rsync_Start() {
    20    Rsync_Port1=`netstat -lntup |grep -c  0.0.0.0:873`
    21    if [ $Rsync_Port1 -ne 0 ]
    22      then
    23       action  "服务已启动" /bin/false
    24       exit 3
    25    else
    26       $Rsync_COM1
    27       #action  "Rsync 启动" /bin/true
    28       QiDong
    29    fi
    30 }
    31
    32 Rsync_Stop() {
    33    Rsync_Port2=`netstat -lntup |grep -c  0.0.0.0:873`
    34    if [ $Rsync_Port2 -eq 0 ]
    35      then
    36        action  "服务未启动" /bin/false
    37        exit 3
    38    else
    39        $Rsync_COM2
    40        #action  "Rsync 停止" /bin/true
    41        TingZhi
    42    fi
    43 }
    44
    45 Rsync_Status() {
    46    if [ $Rsync_Port -eq 1 ]
    47      then
    48        echo  "Rsync 服务运行中..."
    49    else
    50        echo  "Rsync 服务未运行"
    51    fi
    52 }
    53
    54 Rsync_Restart() {
    55    Rsync_Stop
    56    Rsync_Start
    57 }
    58 COMMAND=$1
    59
    60 case "$COMMAND" in
    61   start)
    62     Rsync_Start
    63     ;;
    64   stop)
    65     Rsync_Stop
    66     ;;
    67   status)
    68     Rsync_Status
    69     ;;
    70   restart|reload|force-reload)
    71     Rsync_Restart
    72     ;;
    73   *)
    74     echo $"Usage: $0 {start|stop|status|restart|reload|force-reload}"
    75     exit 2
    76 esac

    View Code rsync 服务管理脚本

    脚本执行过程

     

    2.4.3 【练习题3】菜单自动化软件部署脚本实践

    综合实例:打印选择菜单,按照选择一键安装不同的Web服务。

    示例菜单:

    [root@oldboy scripts]# sh menu.sh

        1.[install lamp]

        2.[install lnmp]

        3.[exit]

        pls input the num you want:

    要求:

      1、当用户输入1时,输出“start installing lamp.提示”然后执行/server/scripts/lamp.sh,脚本内容输出"lampis installed"后退出脚本,工作中就是正式lamp一键安装脚本;

    echo 'echo lampis installed' > /server/scripts/lamp.sh
    chmod +x /server/scripts/lamp.sh

      2、当用户输入2时,输出“start installing lnmp.提示” 然后执行/server/scripts/lnmp.sh输出"lnmpis installed"后退出脚本,工作中就是正式lnmp一键安装脚本;

    echo 'echo lnmpis installed' > /server/scripts/lnmp.sh
    chmod +x /server/scripts/lnmp.sh

      3、当输入3时,退出当前菜单及脚本;  

      4、当输入任何其它字符,给出提示“Input error”后退出脚本;

      5、要对执行的脚本进行相关的条件判断,例如:脚本文件是否存在,是否可执行等判断。

    脚本 内容

    自动化软件部署脚本

    1 [root@clsn scripts]# cat menu.sh
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: menu.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-07 19:29:30
    9 # Description:
    10 #############################################################
    11
    12 cat <<EOF
    13 1.[install lamp]
    14 2.[install lnmp]
    15 3.[exit]
    16 EOF
    17
    18 read -p "please input the num you want:" Num
    19
    20 case "$Num" in
    21   1)
    22     if [ -f /server/scripts/lamp.sh ]
    23       then
    24          echo -e "\033[36mstart installing lamp\033[0m"
    25          /server/scripts/lamp.sh
    26     else
    27       echo -e "\033[5;41;37m /server/scripts/lamp.sh 文件不存在 \033[0m"
    28     fi
    29     ;;
    30   2)
    31     if [ -f /server/scripts/lnmp.sh ]
    32       then
    33          echo -e "\033[36mstart installing lnmp\033[0m"
    34         /server/scripts/lnmp.sh
    35     else
    36       echo -e "\033[5;41;37m /server/scripts/lnmp.sh 文件不存在 \033[0m"
    37     fi
    38     ;;
    39   3)
    40     exit
    41     ;;
    42   *)
    43     echo -e "\033[31mInput error \033[0m"
    44     exit 2
    45 esac

     

    执行过程

     

    2.4.4 if 与 case 对比

      if 语句类似黑名单,需要把这种错误场景封堵

      case 语句类似白名单,只要把正确结果列完整即可

    2.5 其他补充说明

    2.5.1 linux中产生随机数的方法

    [root@clsn scripts]# echo $RANDOM
    29291
    [root@clsn scripts]# echo $RANDOM
    5560
    [root@clsn scripts]# echo $RANDOM
    2904

    2.5.2 echo 命令输出带颜色字符

    # 彩色字体

    echo -e "\033[30m 黑色字 clsn \033[0m"
    echo -e "\033[31m 红色字 clsn \033[0m"
    echo -e "\033[32m 绿色字 clsn \033[0m"
    echo -e "\033[33m 黄色字 clsn \033[0m"
    echo -e "\033[34m 蓝色字 clsn \033[0m"
    echo -e "\033[35m 紫色字 clsn \033[0m"
    echo -e "\033[36m 天蓝字 clsn \033[0m"
    echo -e "\033[37m 白色字 clsn \033[0m"

    效果示意图

     

    # 彩色底纹

    echo -e "\033[40;37m 黑底白字 clsn \033[0m"
    echo -e "\033[41;37m 红底白字 clsn \033[0m"
    echo -e "\033[42;37m 绿底白字 clsn \033[0m"
    echo -e "\033[43;37m 黄底白字 clsn \033[0m"
    echo -e "\033[44;37m 蓝底白字 clsn \033[0m"
    echo -e "\033[45;37m 紫底白字 clsn \033[0m"
    echo -e "\033[46;37m 天蓝白字 clsn \033[0m

    效果示意图

     

    # 特效字体

    \033[0m 关闭所有属性
    \033[1m 设置高亮度
    \033[4m 下划线
    \033[5m 闪烁
    \033[7m 反显
    \033[8m 消隐
    \033[30m — \033[37m 设置前景色
    \033[40m — \033[47m 设置背景色
    \033[nA 光标上移 n 行
    \033[nB 光标下移 n 行
    \033[nC 光标右移 n 行
    \033[nD 光标左移 n 行
    \033[y;xH 设置光标位置
    \033[2J 清屏
    \033[K 清除从光标到行尾的内容
    \033[s 保存光标位置
    \033[u 恢复光标位置
    \033[?25l 隐藏光标
    \033[?25h 显示光标

    部分效果示意图 

    2.5.3 显示文本中的隐藏字符

    使用cat命令查看文本中的隐藏字符

    [root@clsn ~]# cat --help
    用法:cat [选项]... [文件]...
    将[文件]或标准输入组合输出到标准输出。

      -A, --show-all           等于-vET
      -b, --number-nonblank    对非空输出行编号
      -e                       等于-vE
      -E, --show-ends          在每行结束处显示"$"
      -n, --number             对输出的所有行编号
      -s, --squeeze-blank      不输出多行空行
      -t                       与-vT 等价
      -T, --show-tabs          将跳格字符显示为^I
      -u                       (被忽略)
      -v, --show-nonprinting   使用^ 和M- 引用,除了LFD和 TAB 之外

    使用cat -A查看隐藏的字符

    [root@clsn ~]# cat -A /etc/hosts
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4$
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6$
    10.0.0.1 mirrors.aliyuncs.com mirrors.aliyun.com$
    10.0.0.180 clsn$

    关于隐藏字符常见错误

    在windows中编写的脚本换行使用的是 \r\n

             但是在linux中使用\n 进行换行

    [root@clsn ~]# cat -A windowe.sh
    n1=2^M$
    n2=1^M$
    ^M$
    [ $n1 -gt $n2 ] && echo "$n1 > $n2" && exit^M$
    [ $n1 -eq $n2 ] && echo "$n1 = $n2" && exit^M$
    echo "$n1 < $n2"^M$

    使用dos2unix 把windows上的脚本转化linux格式

    [root@clsn ~]# dos2unix windowe.sh
    dos2unix: converting file windowe.sh to Unix format ...

    转换后,脚本的内容隐藏内容改变。

    [root@clsn ~]# cat -A windowe.sh
    n1=2$
    n2=1$
    $
    [ $n1 -gt $n2 ] && echo "$n1 > $n2" && exit$
    [ $n1 -eq $n2 ] && echo "$n1 = $n2" && exit$
    echo "$n1 < $n2"$

    2.5.4 排错技巧

    sh -x  脚本.sh

    -x 开启脚本调试模式

    cat -A  文件.txt

    -A  查看文件的隐藏字符

    2.5.5 shell 脚本段注释方法

    方法一:

    <<EOF
      内容
    EOF

    方法二:

    一行注释方法 → : '内容'
    段注释方法 ↓
    :'
    http://blog.znix.top
    '

    :命令的说明

    [root@clsn scripts]# help :
    :: :
        空的命令。
       
        没有效果; 此命令不做任何操作。
       
        退出状态:
        总是成功。

    :命令的应用场景

    if 条件
      then
        :
    else
        命令
    fi

    2.5.6 其他补充

      类进度条效果

    yum install -y pv
    echo {1..20}|pv -qL 15

      clear 命令

    清屏 == ctrl + l

    Shell编程进阶篇(完结) 

    3.1 for循环语句

         在计算机科学中,for循环(英语:for loop)是一种编程语言的迭代陈述,能够让程式码反复的执行。

         它跟其他的循环,如while循环,最大的不同,是它拥有一个循环计数器,或是循环变数。这使得for循环能够知道在迭代过程中的执行顺序。

    1.1.1 shell中的for循环

             shell中的for 循环与在c中不同,它包含三种形式:第一种结构是列表for 循环;第二种结构就是不带列表的for循环;第三种就类似于C语言。

    ①   列表for循环(常用)

    #!/bin/bash

    for i in 取值列表

    do

        循环主体/命令

    done

     

    ②   不带列表for循环(示例)

    #!/bin/absh

    echo "惨绿少年的博客是:" 

    for i

         do  

         echo "$i"

    done

       脚本执行结果

    [root@clsn for]# sh  for2.sh http://blog.znix.top

    惨绿少年的博客是:

    http://blog.znix.top

     

     

    ③   类似C语言的风格(这种用法常在C语语言中使用)

    for((exp1;exp2;exp3))
        do
          指令...
    done  

             编写类似C语言风格脚本

    for((i=0;i<=3;i++))
        do
          echo $i
    done 

             脚本执行过程

     

    3.1.2 不同语言的For循环

    Shell中的两种样式

    # 样式一:
    for i in 1 2 3
      do
        echo $i
    done
    # 样式二:
    for i in 1 2 3;do  echo $i;done

      JAVA

    for(int i = 0; i < 5; i++){
        //循环语句;
    }

      PHP

    for ($i = 0; $i < 5; $i++) {
      # statements;
    }

    For i = 1 To 5
    ===PASCAL===
    for not i=1 do
    begin
       i=0;
       writeln('Go on!');
    end.
      
      '循环语句
    Next i

      swift

    var x = 0
    for i in 1...100{
        x += i
    }
    print(x)

    //5050
    for _ in 1...100{
        x += 1
    }
    print(x)
    // 100

    var box = [1,2,3,4,5]
    for i in box{
        print(i)
    }
    /*
    1
    2
    3
    4
    5
    */
    ---

    3.2 for循环相关练习题

    3.2.1 【练习题1】批量生成随机字符文件名案例

    使用for循环在/clsn目录下批量创建10个html文件,其中每个文件需要包含10个随机小写字母加固定字符串clsn,名称示例如下:

    [root@znix C19]# ls /clsn
    apquvdpqbk_clsn.html  mpyogpsmwj_clsn.html  txynzwofgg_clsn.html  
    bmqiwhfpgv_clsn.html  udrzobsprf_clsn.html  vjxmlflawa_clsn.html 
    jhjdcjnjxc_clsn.html  qeztkkmewn_clsn.html jpvirsnjld_clsn.html 
    ruscyxwxai_clsn.html

    脚本内容

    批量生成随机字符文件名

    1 [root@clsn for]# cat make_file.sh
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: make_file.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-08 11:01:19
    9 # Description:
    10 #############################################################
    11
    12 [ -d /clsn ] || mkdir -p /clsn
    13 rpm -qa |grep pwgen &>/dev/null
    14 if [ $? -eq  1 ]
    15   then
    16     yum install pwgen -y &>/dev/null
    17 fi
    18
    19 cd /clsn &&\
    20 for i in {1..10}
    21   do
    22    #File_Name=`uuidgen |tr "0-9-" "a-z"|cut -c 1-10`
    23    File_Name2=`pwgen -1A0 10`
    24    touch ${File_Name2}_clsn.html
    25 done

    脚本执行结果

    [root@clsn for]# ls -l  /clsn
    -rw-r--r-- 1 root root 0 12月  8 19:41 aegheiriek_clsn.html
    -rw-r--r-- 1 root root 0 12月  8 19:41 aifohxique_clsn.html
    -rw-r--r-- 1 root root 0 12月  8 19:41 caexahween_clsn.html
    -rw-r--r-- 1 root root 0 12月  8 19:41 ciefaivaib_clsn.html
    -rw-r--r-- 1 root root 0 12月  8 19:41 eixongooph_clsn.html
    -rw-r--r-- 1 root root 0 12月  8 19:41 foozaivedo_clsn.html
    -rw-r--r-- 1 root root 0 12月  8 19:41 ireeteethu_clsn.html
    -rw-r--r-- 1 root root 0 12月  8 19:41 ohmeebivae_clsn.html
    -rw-r--r-- 1 root root 0 12月  8 19:41 oiceehahth_clsn.html
    -rw-r--r-- 1 root root 0 12月  8 19:41 sheewaehoo_clsn.html

    3.2.2 【练习题2】批量改名特殊案例

    【练习题1】中结果文件名中的clsn字符串全部改成znix(最好用for循环实现),并且将扩展名html全部改成大写。

    jpvirsnjld_clsn.html   ===> jpvirsnjld_znix.HTML

    脚本内容:

    批量改名

    1 [root@clsn for2]# cat rename_file.sh
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: rename_file.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-08 11:31:56
    9 # Description:
    10 #############################################################
    11
    12 cd /clsn &&\
    13 File_name=`ls |sed -r 's#(.*)_clsn.html#\1#g'`
    14
    15 for i in $File_name
    16   do
    17    if [ -f ${i}_clsn.html ]
    18      then
    19      mv ${i}_clsn.html ${i}_znix.HTML
    20    else
    21      echo "文件修改完成."
    22      exit
    23    fi
    24 done

    查看结果

    [root@clsn for2]# ls /clsn/
    aeyaesughi_znix.HTML  caireasipi_znix.HTML  uahahnieli_znix.HTML
    aifaepheeb_znix.HTML  eathixoong_znix.HTML  zalipageen_znix.HTML
    akuipheeye_znix.HTML  ietoothaik_znix.HTML
    apheikieno_znix.HTML  lachohtaif_znix.HTML

    3.2.2.1  批量改名其他方式

      rename 方式(最方便,专业改名)

    rename txt jpg *

      非 for 循环方式批量改名(使用sed命令进行拼接,然后交给bash执行)

    ls *jpg|sed -r 's#(.*).jpg#mv &  \1.mp4#'|bash

    3.2.3 【练习题3】批量创建特殊要求用户案例

      批量创建10个系统帐号clsn01-clsn10并设置密码(密码为随机数,要求字符和数字等混合)。

    脚本内容:

    批量创建特殊要求用户

    1 [root@clsn for2]# cat add_user.sh
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: add_user.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-08 11:52:21
    9 # Description:
    10 #############################################################
    11
    12 Passwd_File=/tmp/`uuidgen`.txt
    13 >$Passwd_File
    14 chmod 400 $Passwd_File
    15
    16 for i in clsn{01..10}
    17   do
    18    userdel -r "$i" &>/dev/null
    19    id $i &>/dev/null
    20    if [ $? -ne 0 ]
    21      then
    22        useradd $i
    23        PassWd=`uuidgen`
    24        echo $PassWd |passwd --stdin $i &>/dev/null
    25        echo "用户名:$i  密码:$PassWd" >>$Passwd_File
    26        echo -e "\033[32m $i 用户创建成功!\033[0m"
    27    else
    28      echo "$i 用户已存在"
    29    fi
    30    if [ "$i" == "clsn10" ]
    31      then
    32        echo "用户密码请查看文件 $Passwd_File"
    33    fi
    34 done

    查看成的密码文件

    [root@clsn for2]# cat /tmp/3e5c18d9-f878-4d06-931e-5bbcc810c3dc.txt
    用户名:clsn01  密码:3d4644d0-9cf4-49db-8928-1a8346972c32
    用户名:clsn02  密码:70798c3a-c8e3-42a0-9942-d4011ce4b4b3
    用户名:clsn03  密码:db2a0f1d-2e49-44f5-a5b2-69b352b30120
    用户名:clsn04  密码:62d2e0c6-b755-4b00-ad2d-c98f9ca9f258
    用户名:clsn05  密码:eaa3471b-d04f-4d7c-8b7e-3d75172a483b
    用户名:clsn06  密码:fb260a11-cd47-4b97-ab49-0cae7a755262
    用户名:clsn07  密码:16ee7a1f-8aac-4537-b1aa-7fc75beb8754
    用户名:clsn08  密码:0dde8823-b97d-4c88-9258-3a68a3b53eba
    用户名:clsn09  密码:daf14ec4-ba9f-4593-9773-1557fdf605dc
    用户名:clsn10  密码:6f1b452c-00b2-44a1-9f43-5f658d3a9124

    脚本执行过程:

     

     

    3.2.3.1  批量创建用户并设置随机密码(不使用shell循环)

      方法一

    echo user{1..20}|xargs -n1|sed -r 's#(.*)#useradd \1 \&\& echo \1 >>/tmp/passwd.txt \&\& echo $RANDOM |md5sum |cut -c 1-5>>/tmp/passwd.txt \&\& echo `tail -1 /tmp/passwd.txt`|passwd --stdin \1#g'|bash

      方法二

    echo user{1..20}|xargs -n1|sed -r 's#(.*)#useradd \1 \&\& pass=`echo $RANDOM |md5sum |cut -c 1-5` \&\& echo $pass |passwd --stdin \1 \&\& echo \1 $pass>>/tmp/user_passwd.txt#g'|bash

      方法三

    echo user{1..20}|xargs -n1|sed -r 's#(.*)#useradd \1 \&\& pass=`echo $RANDOM |md5sum |cut -c 1-5` \&\& echo \1:$pass>>/tmp/user_passwd.txt \&\& chpasswd</tmp/user_passwd.txt#g'|bash

    3.2.4 【练习题4】扫描网络内存活主机案例

      写一个Shell脚本,判断10.0.0.0/24网络里,当前在线的IP有哪些?

    脚本内容:

    扫描网络内存活主机

    1 [root@clsn for]# cat scan_ip2.sh
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: scan_ip.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-07 21:58:47
    9 # Description:
    10 #############################################################
    11
    12 Ip_File=/tmp/scan_ip.txt
    13 >$Ip_File
    14
    15 for i in 10.0.0.{1..254}
    16  do
    17   ping -c 1 -W 1 $i &>/dev/null && \
    18   if [ $? -eq 0 ] ;then
    19     echo "存活主机: $i" &>>$Ip_File
    20   fi &  
    21 done
    22 echo "使用 cat $Ip_File 查看扫描结果"

    脚本执行结果

    [root@clsn for]# time sh scan_ip2.sh
    使用 cat /tmp/scan_ip.txt 查看扫描结果

    real    0m0.290s
    user    0m0.001s
    sys    0m0.039s

    [root@clsn for]#  cat /tmp/scan_ip.txt
    存活主机: 10.0.0.180
    存活主机: 10.0.0.254

    3.2.5 【练习题5】筛选符合长度的单词案例

      利用bash for循环打印下面这句话中字母数不大于6的单词(某企业面试真题)。

        I am clsn Welcome to my blog http://blog.znix.top

    脚本内容:

    筛选符合长度的单词

    1 [root@clsn for]# vim  changdu.sh
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: changdu.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-07 22:36:48
    9 # Description:
    10 #############################################################
    11
    12 Word='I am clsn Welcome to my blog http://blog.znix.top'
    13
    14 for i in $Word
    15  do
    16   #[ ${#i} -le 6 ]  && echo $i  #子串方法
    17   a=`echo $i |wc -L`
    18   if [ $a -le 6 ]
    19     then
    20       echo $i
    21    fi
    22 done

    脚本执行结果

    [root@clsn for]# sh changdu.sh
    I
    am
    clsn
    to
    my
    blog

    方法二:

    read -p "请输入要判断的语句:" a
    set -- $a
    for i in "$@"
      do
        if [ ${#i} -le 6 ];then
           echo "$i"
        fi
    done

     由 https://home.cnblogs.com/u/1233234   @贰佰  提供

    使用expr 计算字符串长度

    [root@clsn scripts]# expr length '111'
    3

    3.2.6 【练习题6】破解RANDOM随机数案例

      已知下面的字符串是通过RANDOM随机数变量md5sum后,再截取一部分连续字符串的结果,请破解这些字符串对应的使用md5sum处理前的RANDOM对应的数字?

      21029299
      00205d1c
      a3da1677
      1f6d12dd
      890684b

    脚本内容

    破解RANDOM随机数

    [root@clsn for]# vim  pojie.sh
    #!/bin/bash
    #############################################################
    # File Name: pojie.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-07 22:41:01
    # Description:
    #############################################################

    md5File=/tmp/Randow_Md5.txt
    Md5_Word="21029299 00205d1c a3da1677 1f6d12dd 890684b"

    if [ ! -f $md5File ]
      then
        >$md5File
        for i in {0..32767}
           do
            echo `echo $i |md5sum` $i  >> $md5File
        done
    else
        for num in $Md5_Word
          do
           grep $num $md5File
        done
    fi

    脚本执行结果

    [root@clsn for]# sh  pojie.sh
    2102929901ee1aa769d0f479d7d78b05 - 25667
    00205d1cbbeb97738ad5bbdde2a6793d - 1346
    a3da1677501d9e4700ed867c5f33538a - 25345
    1f6d12dd61b5c7523f038a7b966413d9 - 7041
    890684ba3685395c782547daf296935f - 10082

    3.2.7 【练习题7】博客园博文爬虫案例

      获取博客园(惨绿少年)博客列表倒序排序考试题

    需求如下:

      请把https://www.cnblogs.com/clsn/地址中的所有博文,按照时间倒序列表如下:

        2017年12月8日  Shell编程基础篇-下

        http://www.cnblogs.com/clsn/p/8006210.html

        2017年12月7日   memcached 缓存数据库应用实践

        http://www.cnblogs.com/clsn/p/7999510.html

    高级要求:

      生成html页面,并设置超链接。

      结果如改网页展示:http://www.cnblogs.com/clsn/p/8007232.html

    脚本内容:

    博客园博文爬虫案例

    1 [root@clsn htmp]# cat clsn_blog.sh
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: clsn_blog.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-08 21:19:12
    9 # Description:
    10 #############################################################
    11
    12 Uri='http://www.cnblogs.com/clsn/default.html?page='
    13
    14 clsn_Html=/tmp/html/clsn.html
    15 mkdir -p /tmp/html/
    16 >$clsn_Html
    17
    18 for i in {1..6}
    19   do
    20     curl -s  $Uri$i |grep -A 5  'ImageLink' |sed  's#<.*div.*># #g'|sed 's#--#<br>#g' >> $clsn_Html
    21     echo '<br>' >>$clsn_Html
    22 done

    脚本成网页文件

     

    3.2.7.1  51CTO博客爬虫案例

    脚本内容

    51CTO博客爬虫

    1 [root@clsn html]# cat oldboy_blog.sh
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: oldboy_blog.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-08 22:30:57
    9 # Description:
    10 #############################################################
    11
    12 Uri='http://blog.51cto.com/oldboy/p'
    13 Blog_Index_File=/tmp/html/oldboy_blog.html
    14 mkdir -p /tmp/html
    15 > /tmp/html/oldboy_blog.html
    16
    17 for i in {1..29}
    18   do
    19   curl -s $Uri$i |grep -A 5  '发布于'  |\
    20        sed '/^.*zan fr.*/,+2d'|\
    21        sed 's#^--$#<br>#g'|\
    22        sed 's#<a.*fl">发布于:#<a>#g'|\
    23        sed 's#<sp.*an>##g' >>\
    24            $Blog_Index_File
    25   echo '<br>' >>$Blog_Index_File
    26 done

    附 文本编码转码

    [root@clsn for]# iconv --help
    用法: iconv [选项...] [文件...]
    转换给定文件的编码。

    输入/输出格式规范:
      -f, --from-code=名称     原始文本编码
      -t, --to-code=名称       输出编码

    信息:
      -l, --list                 列举所有已知的字符集

    输出控制:
      -c                         从输出中忽略无效的字符
      -o, --output=FILE          输出文件
      -s, --silent               关闭警告
          --verbose              打印进度信息

      -?, --help                 给出该系统求助列表
          --usage                给出简要的用法信息
      -V, --version              打印程序版本号

    长选项的强制或可选参数对对应的短选项也是强制或可选的

    常用:

     iconv  -f gb2312  -t utf-8 -c  clsn.html

    3.3 while循环语句

    在编程语言中,while循环(英语:while loop)是一种控制流程的陈述。利用一个返回结果为布林值(Boolean)的表达式作为循环条件,当这个表达式的返回值为“真”(true)时,则反复执行循环体内的程式码;若表达式的返回值为“假”(false),则不再执行循环体内的代码,继续执行循环体下面的代码。

             因为while循环在区块内代码被执行之前,先检查陈述是否成立,因此这种控制流程通常被称为是一种前测试循环(pre-test loop)。相对而言do while循环,是在循环区块执行结束之后,再去检查陈述是否成立,被称为是后测试循环。

     

    3.3.1 shell中while语法

    while 条件
      do
        命令
    done

    3.3.2 while 使用场景

             多用于创建守护进程

    【示例1】:while实现web服务器搭建

             脚本代码

    [root@clsn scripts]# vim web_view.sh
    #!/bin/bash
    #############################################################
    # File Name: web_view.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-11 10:07:24
    # Description:
    #############################################################
    while true
      do
      echo "ok" | nc -l 81
    done

      客户端进行访问测试

    [root@clsn html]# curl 10.0.0.180:81
    ok

      服务端显示结果:

    【示例2】:while创建定时任务

             脚本内容:

    #!/bin/bash
    while  true
      do
        uptime
           sleep 0.6
    done

             脚本执行结果

    [root@clsn while]# sh  while1.sh
    15:01:52 up 2 days,  6:02,  3 users,  load average: 0.00, 0.01, 0.05
    15:01:53 up 2 days,  6:02,  3 users,  load average: 0.00, 0.01, 0.05
    15:01:53 up 2 days,  6:02,  3 users,  load average: 0.00, 0.01, 0.05
    15:01:54 up 2 days,  6:02,  3 users,  load average: 0.00, 0.01, 0.05
    15:01:55 up 2 days,  6:02,  3 users,  load average: 0.00, 0.01, 0.05
    15:01:55 up 2 days,  6:02,  3 users,  load average: 0.00, 0.01, 0.05

    说明:

             sleep 与 usleep

    sleep 单位 秒  sleep 1 休息1秒

    usleep 单位 微秒 usleep 1000000 休息1s

    1微秒等于百万分之一秒(10的负6次方秒)

    时间测试

    [root@clsn while]# time sleep 0.1

    real    0m0.102s
    user    0m0.001s
    sys    0m0.000s

    3.3.3 while 作用

      补充定时任务功能,执行小于1秒的定时任务

      循环执行某些操作,例如水果菜单

              见上文

    示例1:使用while循环实现水果菜单的重复使用  

             脚本内容

    使用while循环实现水果菜单的重复使用

             脚本执行过程

     

    示例2:计算1-100的和

      方法一 (bc命令实现)

    echo `seq -s + 1 100`|bc

      方法二(while循环方法)

    [root@clsn while]# cat jishan.sh
    #!/bin/bash
    #############################################################
    # File Name: jishan.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-09 15:18:44
    # Description:
    #############################################################

    i=1

    while [ "$i" -le 100 ]
      do
      ((b=b+i))
      ((i++))
    done
    echo $b

    示例3:实现类似手机通讯计费功能

             脚本内容:

    实现类似手机通讯计费功能

    1 [root@clsn scripts]# cat while/shouji.sh
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: shouji.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-09 15:56:09
    9 # Description:
    10 #############################################################
    11 sum=1000
    12 i=15
    13
    14
    15 while [ $sum -ge 15 ]
    16   do
    17 cat<<EOF
    18 =================
    19 1.发短信
    20 2.查余额
    21 3.账户充值
    22 4.退出
    23 =================
    24 EOF
    25     read -p "你要做什么呢?" Some
    26     case "$Some" in
    27       1)
    28         sum=$((sum-i))
    29         read -p  "请输入发送短信的内容:"
    30         read -p  "请输入收信人:"
    31         sleep 0.3
    32         echo "发送成功."
    33         echo "您当前余额为$sum"
    34         ;;
    35       2)
    36         echo "您当前余额为$sum"
    37         ;;
    38       3)
    39         read -p "请输入你要充值的金额:" ChongZhi
    40         sum=$((sum+ChongZhi))
    41         echo "充值成功,当前余额为$sum"
    42         ;;
    43       4)
    44         exit
    45         ;;
    46       *)
    47         echo "输入有误!"
    48         exit 2
    49     esac
    50 done
    51
    52 echo "余额不足,请及时充值!"

     

    3.4 获取取文件中的行,单词和字符

    3.4.1 迭代获取文件中的每一行

    方法一

    while read line;
      do
        echo $line;
    done < file.txt

    方法二

    cat file.txt|while read line
      do
    echo $line
    done

    方法三

    exec < file.txt
    while read line;
      do
        echo line;
    done

    3.4.2 迭代获取每一个单词

    for word in $line;
      do
        echo $word;
    done

    3.4.3 迭代获取每一个字符

    3.4.4 同时获取取文件中的行,单词和字符脚本

    脚本内容

    #!/bin/bash
    n=1
    while read i
      do
       echo "第${n}行 $i"
       m=1
       for x in $i
         do
           echo "第${m}个单词 $x"
           echo $x|grep -o .
           ((m++))
       done
       ((n++))
    done < $1

    脚本执行结果:

    同时获取取文件中的行,单词和字符脚本 执行结果

      1 [root@clsn scripts]# sh  lunxun.sh  /etc/hosts
      2 第1行 127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
      3 第1个单词 127.0.0.1
      4 1
      5 2
      6 7
      7 .
      8 0
      9 .
    10 0
    11 .
    12 1
    13 第2个单词 localhost
    14 l
    15 o
    16 c
    17 a
    18 l
    19 h
    20 o
    21 s
    22 t
    23 第3个单词 localhost.localdomain
    24 l
    25 o
    26 c
    27 a
    28 l
    29 h
    30 o
    31 s
    32 t
    33 .
    34 l
    35 o
    36 c
    37 a
    38 l
    39 d
    40 o
    41 m
    42 a
    43 i
    44 n
    45 第4个单词 localhost4
    46 l
    47 o
    48 c
    49 a
    50 l
    51 h
    52 o
    53 s
    54 t
    55 4
    56 第5个单词 localhost4.localdomain4
    57 l
    58 o
    59 c
    60 a
    61 l
    62 h
    63 o
    64 s
    65 t
    66 4
    67 .
    68 l
    69 o
    70 c
    71 a
    72 l
    73 d
    74 o
    75 m
    76 a
    77 i
    78 n
    79 4
    80 第2行 ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    81 第1个单词 ::1
    82 :
    83 :
    84 1
    85 第2个单词 localhost
    86 l
    87 o
    88 c
    89 a
    90 l
    91 h
    92 o
    93 s
    94 t
    95 第3个单词 localhost.localdomain
    96 l
    97 o
    98 c
    99 a
    100 l
    101 h
    102 o
    103 s
    104 t
    105 .
    106 l
    107 o
    108 c
    109 a
    110 l
    111 d
    112 o
    113 m
    114 a
    115 i
    116 n
    117 第4个单词 localhost6
    118 l
    119 o
    120 c
    121 a
    122 l
    123 h
    124 o
    125 s
    126 t
    127 6
    128 第5个单词 localhost6.localdomain6
    129 l
    130 o
    131 c
    132 a
    133 l
    134 h
    135 o
    136 s
    137 t
    138 6
    139 .
    140 l
    141 o
    142 c
    143 a
    144 l
    145 d
    146 o
    147 m
    148 a
    149 i
    150 n
    151 6
    152 第3行 10.0.0.1 mirrors.aliyuncs.com mirrors.aliyun.com
    153 第1个单词 10.0.0.1
    154 1
    155 0
    156 .
    157 0
    158 .
    159 0
    160 .
    161 1
    162 第2个单词 mirrors.aliyuncs.com
    163 m
    164 i
    165 r
    166 r
    167 o
    168 r
    169 s
    170 .
    171 a
    172 l
    173 i
    174 y
    175 u
    176 n
    177 c
    178 s
    179 .
    180 c
    181 o
    182 m
    183 第3个单词 mirrors.aliyun.com
    184 m
    185 i
    186 r
    187 r
    188 o
    189 r
    190 s
    191 .
    192 a
    193 l
    194 i
    195 y
    196 u
    197 n
    198 .
    199 c
    200 o
    201 m
    202 第4行 10.0.0.180 clsn
    203 第1个单词 10.0.0.180
    204 1
    205 0
    206 .
    207 0
    208 .
    209 0
    210 .
    211 1
    212 8
    213 0
    214 第2个单词 clsn
    215 c
    216 l
    217 s
    218 n

    3.4.5 eval 命令用法

    [root@clsn ~]# clsn=6
    [root@clsn ~]# echo {1..$clsn}
    {1..6}
    [root@clsn ~]# eval echo {1..$clsn}
    1 2 3 4 5 6

       eval 命令的说明

    [root@clsn ~]# help eval
    eval: eval [参数 ...]
        将参数作为 shell 命令执行。
       
        将 ARGs 合成一个字符串,用结果作为 shell 的输入,
        并且执行得到的命令。
       
        退出状态:
        以命令的状态退出,或者在命令为空的情况下返回成功。

    3.5 break continue exit return

    条件与循环控制及程序返回值命令表 

    命令

    说明

    break n   

    如果省略n,则表示跳出整个循环,n表示跳出循环的层数

    continue n

    如果省略n,则表示跳过本次循环,忽略本次循环的剩余代码,进人循环的下一次循环。 n表示退到第n层继续循环

    exit n

    退出当前Shell程序,n为上一次程序执行的状态返回值。n也可以省略,在下一个Shell里可通过"$?"接收exit n的n值

    return n

    用于在函数里作为函数的返回值,以判断函数执行是否正确。在下一个Shell里可通过"$?"接收exit n的n值

    简单来说即:

    break    跳出循环
    continue 跳出本次循环
    exit     退出脚本
    return   与 exit 相同,在函数中使用

    3.5.1 break命令说明

    [root@clsn scripts]# help break
    break: break [n]
        退出 for、while、或 until 循环
       
        退出一个 FOR、WHILE 或 UNTIL 循环。如果指定了N,则打破N重
        循环
       
        退出状态:
        退出状态为0除非 N 不大于或等于 1。

      测试脚本内容

    break 测试脚本

    1 #!/bin/bash
    2
    3 for i in {1..5}
    4
    5   do
    6
    7     if [ $i -eq 3 ]
    8
    9       then
    10
    11        break
    12
    13     fi
    14
    15     echo $i
    16
    17 done
    18
    19 echo "ok"

     

      脚本执行结果

    [root@clsn scripts]# sh break.sh
        1
        2
        ok

    3.5.2 continue命令说明

    [root@clsn scripts]# help continue
    continue: continue [n]
        继续 for、while、或 until 循环。
       
        继续当前 FOR、WHILE 或 UNTIL 循环的下一步。
        如果指定了 N, 则继续当前的第 N 重循环。
       
        退出状态:
        退出状态为 0 除非 N 不大于或等于1。

      测试脚本内容

    continue 测试脚本

    1 #!/bin/bash
    2     for i in {1..5}
    3       do
    4         if [ $i -eq 3 ]
    5           then
    6             continue
    7         fi
    8         echo $i
    9     done
    10     echo "ok"

     

      脚本执行结果

    [root@clsn scripts]# sh continue.sh
    1
    2
    4
    5
    ok

    3.5.3 exit命令说明

    [root@clsn scripts]# help exit
    exit: exit [n]
        退出shell。
       
        以状态 N 退出 shell。  如果 N 被省略,则退出状态
        为最后一个执行的命令的退出状态。

      测试脚本内容

    exit 测试脚本

    1     #!/bin/bash
    2     for i in {1..5}
    3       do
    4         if [ $i -eq 3 ]
    5           then
    6             exit
    7         fi
    8         echo $i
    9     done
    10     echo "ok"

     

      脚本执行结果

        [root@clsn scripts]# sh exit.sh
        1
        2

    3.5.4 return命令说明

    [root@clsn tuichu]# help return
    return: return [n]
        从一个 shell 函数返回。
       
        使一个函数或者被引用的脚本以指定的返回值 N 退出。
        如果 N 被省略,则返回状态就是
        函数或脚本中的最后一个执行的命令的状态。
       
        退出状态:
        返回 N,或者如果 shell 不在执行一个函数或引用脚本时,失败。

    3.6 shell中的数组

    3.6.1 为什么会产生Shell数组

      通常在开发Shell脚本时,定义变量采用的形式为“a=l;b=2;C=3”,可如果有多个 变量呢?这时再逐个地定义就会很费劲,并且要是有多个不确定的变量内容,也会难以 进行变量定义,此外,快速读取不同变量的值也是一件很痛苦的事情,于是数组就诞生 了,它就是为了解决上述问题而出现的。

    3.6.2 什么是Shell数组

      Shell的数组就是一个元素集合,它把有限个元素(变量或字符内容)用一个名字来 命名,然后用编号对它们进行区分。这个名字就称为数组名,用于区分不同内容的编 号就称为数组下标。组成数组的各个元素(变量)称为数组的元素,有时也称为下标变量。

    3.6.3 数组中的增删改查

    数组的定义

    # 定义数组
    [root@clsn scripts]# stu=(001 002 003)
    # 打印数组
    [root@clsn scripts]# echo ${stu[@]}
    001 002 003
    # 显示数组长度
    [root@clsn scripts]# echo ${#stu}
    3

    查: 遍历数组的内容

    # 打印数组内容(通过数组下标或索引)
    [root@clsn scripts]# echo ${stu[0]}
    001
    [root@clsn scripts]# echo ${stu[1]}
    002
    [root@clsn scripts]# echo ${stu[2]}
    003
    [root@clsn scripts]# echo ${stu[3]}

    # 遍历数组
      方法一
    [root@clsn scripts]# for i in ${stu[@]};do echo $i ;done
    001
    002
    003
        # 方法二
    [root@clsn scripts]# array=(1 2 3 4 5)
    [root@clsn scripts]# for i in `eval echo {1..${#array[@]}}`;do echo ${array[i-1]};done
    1
    2
    3
    4
    5

    增:数组添加

    [root@clsn scripts]# stu[3]=004
    [root@clsn scripts]# echo ${stu[@]}
    001 002 003 004

    改:数组修改

    [root@clsn scripts]# stu[2]=000
    [root@clsn scripts]# echo ${stu[@]}
    001 002 000 004

    删:数组删除

    [root@clsn scripts]# unset stu[2]
    [root@clsn scripts]# echo ${#stu[@]}
    3
    [root@clsn scripts]# echo ${stu[@]}
    001 002 004

    3.6.4 将命令的结果赋值给数组

    dir=(`ls`)
    dir=($(ls))

    命令定义数组

    [root@clsn scripts]# COM=(`ls`)
    [root@clsn scripts]# echo ${COM[@]}
    bianliang.sh case cfb.sh chanshu.sh check check_url.sh

    clsn.sh clsn_test.sh daojishi.sh ddos_check.sh echo.sh for for2 fruits.sh

    function fz.sh html jingdutiao.sh jishuanqi2.sh jishuanqi.sh lamp.sh lnmp.sh

    memcache_check.sh menu.sh nginx.sh panduan panduan1 play quanju.sh rsync_check.sh

    rsyncd system6 tuichu web_check.sh web_view.sh while xiugaizhuji.sh yhk.sh yunshuan.sh

    zhuajiu.sh

    3.6.1 数组定义格式

    [root@clsn scripts]# a=(1 2 3 )
    [root@clsn scripts]# b=(1
    > 2
    > 3
    > 4
    > )
    [root@clsn scripts]# echo ${a[@]}
    1 2 3
    [root@clsn scripts]# echo ${b[@]}
    1 2 3 4

    3.6.2 数组的本质就是一个变量,只是这个变量存了多个值

    在shell 常用的功能是查

       array=(valuel value2 value3 ...)

    打印数组格式

    ${array[@]} 所有元素
    ${#array[@]}  数组长度
    ${array[i]}  单个元素,i是下标

    3.6.3 【练习题】批量检查多个网站地址是否正常

    要求:

      1、使用shell数组方法实现,检测策略尽量模拟用户访问。

      2、每10秒钟做一次所有的检测,无法访问的输出报警。

      3、待检测的地址如下

        http://www.cnblogs.com/clsn/

        http://blog.znix.top

        http://blog.nmtui.com

        http://10.0.0.7

    脚本内容:

    批量检查多个网站地址是否正常

    1 [root@clsn scripts]# cat check_url.sh
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: check_url.sh
    5 # Version: V1.3
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-12 10:44:39
    9 # Description:
    10 #############################################################
    11 url=(
    12 http://www.cnblogs.com/clsn/
    13 http://blog.znix.top
    14 http://blog.nmtui.com
    15 http://10.0.0.7
    16 )
    17 while true
    18   do
    19     for i in ${url[@]}
    20       do
    21       #curl $i &>/dev/null
    22       a=$(curl -I -w "%{http_code}\n" -o /dev/null -s $i)
    23       if [ $a -ne 200 ]
    24         then
    25           echo "$url 异常"
    26       fi
    27     done
    28     sleep 10
    29 done

    3.7 Shell 函数

      shell一个非常重要的特性是它可作为一种编程语言来使用。因为shell是一个解释器,所以它不能对为它编写的程序进行编译,而是在每次从磁盘加载这些程序时对它们进行解释。而程序的加载和解释都是非常耗时的。

       针对此问题,许多shell(如BourneAgainShell)都包含shell函数,shell把这些函数放在内存中,这样每次需要执行它们时就不必再从磁盘读入。shell还以一种内部格式来存放这些函数,这样就不必耗费大量的时间来解释它们。

             函数的作用就是把程序里多次调用相同代码的部分定义成一份,然后起个名字,所有的调用都 只用这名字就可以了,修改代码时,只需要改变函数体内的代码即可。

    3.7.1 使用函数的优势

       ? 把相同的程序段定义成函数,可以减少代码量。

       ? 增加程序的可读、易读性

       ? 实现程序功能的模块化

    3.7.2 定义函数

    function clsn(){
        echo "http://blog.znix.top"
    }

    znix(){
        echo "http://www.znix.top "
    }

    说明:

      1、可以带function clsn() 定义,也可以直接clsn() 定义,不带任何参数。

      2、参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255)

      3、执行函数就是将函数名放到定义的函数之后即可

    将函数加载到当前窗口执行:

    [root@clsn function]# . fun1.sh
    [root@clsn function]# zn
    znew  znix 
    [root@clsn function]# znix
    test
    [root@clsn function]# clsn
    http://blog.znix.top

    3.7.3 引用函数

    脚本内容

    [root@clsn function]# cat  fun2.sh
    #!/bin/bash
    #############################################################
    # File Name: fun2.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-11 19:25:56
    # Description:
    #############################################################
    Fun_File=/server/scripts/function/fun1.sh
    [ -f $Fun_File ] && . $Fun_File
    clsn

    脚本执行结果

    [root@clsn function]# sh  fun2.sh
    http://blog.znix.top

    3.7.4 函数传参

    脚本内容:

    [root@clsn function]# cat fun3.sh
    #!/bin/bash
    #############################################################
    # File Name: fun3.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-12 09:38:48
    # Description:
    #############################################################

    function clsn(){
        echo "Hi "
    }
    CLSN(){
        echo "Hello "
        echo  $0
        echo  $1
        echo  $2

    }
    clsn
    CLSN xi  xi

    脚本执行结果

    [root@clsn function]# sh fun3.sh
    Hi
    Hello
    fun3.sh
    xi
    xi

    3.7.5 $0 永远的脚本名称

    function clsn(){
        echo "http://blog.znix.top $1 $2"
        echo $0
    }

    znix(){
        echo "test"
    }
    clsn $1 $2

    执行结果

    [root@clsn function]# sh  fun1.sh
    http://blog.znix.top 
    fun1.sh

    3.7.6 函数中return的用法

    脚本内容:

    [root@clsn function]# cat  fun3.sh
    #!/bin/bash
    #############################################################
    # File Name: fun3.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-12 09:38:48
    # Description:
    #############################################################

    function clsn(){
        echo "Hi "
    }
    CLSN(){
        echo "Hello "
        echo  $0
        echo  $1
        echo  $2
        return 4
        echo "xxixiixxiix"

    }
    clsn
    CLSN xi  xi
    echo $?

    脚本执行结果

    [root@clsn function]# sh fun3.sh
    Hi
    Hello
    fun3.sh
    xi
    xi
    4

    return命令说明:

    [root@clsn function]# help return
    return: return [n]
        从一个 shell 函数返回。
       
        使一个函数或者被引用的脚本以指定的返回值 N 退出。
        如果 N 被省略,则返回状态就是
        函数或脚本中的最后一个执行的命令的状态。
       
        退出状态:
        返回 N,或者如果 shell 不在执行一个函数或引用脚本时,失败。

    3.7.7 自定义常用函数库

    自定义函数库脚本

    1 #!/bin/bash
    2 #############################################################
    3 # File Name: /server/scripts/userfun.sh
    4 # Version: V1.0
    5 # Author: clsn
    6 # Organization: http://blog.znix.top
    7 # Created Time : 2017-12-12 10:40:04
    8 # Description:
    9 #############################################################
    10
    11 # 脚本初始化
    12 function scripts_init(){
    13   prog=`basename $0 .sh`
    14   LockFile=/var/lock/subsys/${prog}.lock  # 使用锁文件
    15   LogFile=/var/log/${prog}.log  # 脚本记录日志
    16   PidFile=/var/run/${prog}.pid  # 记录进程号,可以管理脚本
    17
    18   [ -f $LockFile ] && echo "There $LockFile is exist!!" && exit 1 ||touch $LockFile
    19   [ ! -f $LogFile ] && touch $LogFile
    20   [ -f $PidFile ] && echo "There $PidFile is exist!!" && exit 2|| echo $$ > $PidFile
    21 }
    22
    23 # 记录日志
    24 function writelog(){
    25   Date=$(date "+%F_%T")
    26   ShellName=`basename $0`
    27   Info=$1
    28   echo "$Date : ${ShellName} : ${Info}" >> ${LogFile}
    29 }
    30
    31 # 脚本退出扫尾
    32 function closeout(){
    33   [ -f $LockFile ] && rm -f $LockFile
    34   [ -f $PidFile ]&& rm -f $PidFile
    35 }
    36
    37 # 判断输入是整数
    38 function int_judge(){
    39   fun_a=$1
    40   expr $fun_a + 1 &>/dev/null
    41   RETVAL=$?
    42   return $RETVAL
    43 }
    44
    45 # 判断输入非空
    46 function input_judge(){
    47   RETVAL=0
    48   fun_a=$1
    49   [ ${#fun_a} -eq 0 ]&& RETVAL=1
    50   return $RETVAL
    51 }

    basename命令

             取出文件名称

    [root@clsn function]# basename /server/scripts/zhuajiu.sh
    zhuajiu.sh
    [root@clsn function]# basename /server/scripts/zhuajiu.sh  .sh
    zhuajiu

    $$ 参数

             取出脚本运行时的pid, 脚本运行的当前进程ID号

    [root@clsn function]# echo $$
    37208
    [root@clsn function]# ps -ef |grep 37208
    root      37208  37206  0 08:39 pts/0    00:00:00 -bash
    root      38578  37208  1 10:33 pts/0    00:00:00 ps -ef
    root      38579  37208  0 10:33 pts/0    00:00:00 grep --color=auto 37208

    引用自定义函数库示例:

    [root@clsn function]# head -22  fun3.sh
    #!/bin/bash
    #############################################################
    # File Name: fun3.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-12 09:38:48
    # Description:
    #############################################################

    . /server/scripts/userfun.sh

    scripts_init
    i=1
    while ((i<=10))
      do
       uptime
       ((i++))
       sleep 1
    done
    closeout

    3.8 shell脚本的调试

    3.8.1 脚本调试技巧

      调试技巧1:使用dos2unix处理脚本

    从windows编辑的脚本到Linux下需要使用这个命令
    dos2unix windows.sh

      调试技巧2:使用echo命令调试

    在变量读取或修改的前后加入echo $变量,也可在后面使用exit退出脚本,这样可以不用注释后面的代码

      调试技巧3:sh -x 脚本  ==》全局调试

    sh -x  scripts.sh

      调试技巧4:局部调试

    set -x
    要调试的脚本内容
    set +x

    3.8.2 Shell调试技巧小结

      ①要记得首先用dos2unix对脚本格式化。

      ②直接执行脚本根据报错来调试,有时报错不准确。

      ③sh -x调试整个脚本,显示执行过程。

      ④set -x和set +x调试部分脚本(在脚本中设置)

      ⑤echo输出变量及相关内容,然后紧跟着exit退出,不执行后面程序的方式,一步步跟踪脚本,对于逻辑错误比较好用。

           写法: echo $var;exit 

      ⑥最关键的是语法熟练、编码习惯、编程思想,将错误扼杀在萌芽之中,减轻调试负担,提高效率。

    3.9 shell编程练习题

    3.9.1 【练习题1】shell实现抓阄程序

    需要使用shell编写一个抓阄的程序:

    要求:

      1、执行脚本后,输入英文名字全拼,产生随机数01-99之间的数字,数字越大评分就去高,前面已经抓到的数字,下次不能在出现相同数字。

      2、第一个输入名字后,屏幕输出信息,并将名字和数字记录到文件里,程序不能退出继续等待别人输入。

             脚本内容:

    抓阄程序 脚本

    1 [root@clsn scripts]# cat zhuajiu.sh
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: zhuajiu.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-10 15:21:27
    9 # Description:
    10 #############################################################
    11 Randow_Temp=/tmp/randow.test
    12 name_Out_File1=/tmp/name_Out_File1.test
    13 name_Out_File2=/tmp/name_Out_File2.test
    14
    15 >$name_Out_File1
    16 >$name_Out_File2
    17 >$Randow_Temp
    18
    19 trap 'echo "请勿使用 Ctrl+c"' 2
    20
    21 Randow() {
    22     sum=`echo $RANDOM |cut -c-2`
    23     grep $sum  $Randow_Temp
    24     if [ $? -eq 0 ];then
    25       Randow
    26     else
    27       echo $sum >>$Randow_Temp
    28       daxiao=$sum
    29     fi
    30 }
    31
    32 Print() {
    33     read -p "请输入名字的拼音:" Name
    34     Randow
    35     echo $Name $daxiao >>$name_Out_File
    36 }
    37
    38 while true
    39 do
    40    clear
    41    echo ""
    42    echo -e  "\033[32m        这个程序会将随机数字排名前三的同学显示出来!\033[0m"
    43    echo -e  "\033[31m                     退出脚本请使用 'exit' \033[0m"
    44    echo ""
    45    head -4 $name_Out_File2
    46    read -p "请输入名字的拼音:" "Name"
    47       if [ "$Name" == exit ]
    48         then
    49           exit
    50       fi
    51    Randow
    52    echo  $daxiao $Name >>$name_Out_File1
    53    echo "随机数最大的三位同学是:"  >$name_Out_File2
    54    sort -k1 -r $name_Out_File1 |column  -t >>$name_Out_File2
    55    clear
    56 done

    脚本执行过程

     

    3.9.2 【练习题2】输出9x9 乘法表

    脚本内容:

    九九乘法表

    1 [root@clsn scripts]# cat cfb.sh
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: cfb.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-11 15:40:03
    9 # Description:
    10 #############################################################
    11 for a in `seq 1 9`
    12 do
    13         for b in `seq 1 9`
    14         do
    15                 if [ $a -ge $b ]
    16                 then
    17                         echo -en "$a x $b = $(expr $a \* $b)  "
    18 
    19                 fi
    20         done
    21 echo " "
    22 done

     

    执行结果

    [root@clsn scripts]# sh  cfb.sh
    1 x 1 = 1  
    2 x 1 = 2  2 x 2 = 4  
    3 x 1 = 3  3 x 2 = 6  3 x 3 = 9  
    4 x 1 = 4  4 x 2 = 8  4 x 3 = 12  4 x 4 = 16  
    5 x 1 = 5  5 x 2 = 10  5 x 3 = 15  5 x 4 = 20  5 x 5 = 25  
    6 x 1 = 6  6 x 2 = 12  6 x 3 = 18  6 x 4 = 24  6 x 5 = 30  6 x 6 = 36  
    7 x 1 = 7  7 x 2 = 14  7 x 3 = 21  7 x 4 = 28  7 x 5 = 35  7 x 6 = 42  7 x 7 = 49  
    8 x 1 = 8  8 x 2 = 16  8 x 3 = 24  8 x 4 = 32  8 x 5 = 40  8 x 6 = 48  8 x 7 = 56  8 x 8 = 64  
    9 x 1 = 9  9 x 2 = 18  9 x 3 = 27  9 x 4 = 36  9 x 5 = 45  9 x 6 = 54  9 x 7 = 63  9 x 8 = 72  9 x 9 = 81

    3.9.3 【练习题3】解决dDOS攻击生产案例

      写一个Shell脚本解决DOS攻击生产案例。

      请根据web日志或者或者网络连接数,监控当某个IP并发连接数或者短时内PV达到100(读者根据实际情况设定),即调用防火墙命令封掉对应的IP。防火墙命令为:iptables-I INPUT -s IP地址 -j DROP。

    练习使用日志下载地址:https://files.cnblogs.com/files/clsn/access-web-log.zip

             脚本内容:

    1 [root@clsn while]# cat ddos_check.sh
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: ddos_check.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-10 12:34:15
    9 # Description:
    10 #############################################################
    11
    12 Info_File=/tmp/ddos_check.log
    13
    14 #从连接数获取
    15 #netstat -lant|awk -F "[ :]+" '/180:80/{clsn[$6]++}END{for(pol in clsn)print pol,clsn[pol]}' >$Info_File
    16
    17 # 从日志获取
    18 awk '{hotel[$1]++}END{for(pol in hotel)print pol,hotel[pol]}' access.log|sort -nk2  -r  >$Info_File
    19
    20 while read line
    21 do
    22     Ip_Add=`echo $line |awk '{print $1}'`
    23     Access=`echo $line |awk '{print $2}'`
    24     if [ $Access -ge 10000 ]
    25     then
    26         #echo $Ip_Add
    27         iptables -I INPUT -s $Ip_Add -j DROP
    28     fi
    29 done <$Info_File

     

    脚本执行结果:

    [root@clsn while]# iptables -L
    Chain INPUT (policy ACCEPT)
    target     prot opt source               destination 
    DROP       all  --  112.64.171.98        anywhere    
    DROP       all  --  58.220.223.62        anywhere    

    Chain FORWARD (policy ACCEPT)
    target     prot opt source               destination 

    Chain OUTPUT (policy ACCEPT)
    target     prot opt source               destination 

    其他方法进行日志分析

      elk日志分析

        http://blog.oldboyedu.com/elk/

      nginx-WAF

        http://blog.oldboyedu.com/nginx-waf/

    3.9.4 【练习题4】开发脚本入侵检测与报警案例(入侵检测系统)

      监控web站点目录(/var/html/www)下所有文件是否被恶意篡改(文件内容被改了),如果有就打印改动的文件名(发邮件),定时任务每3分钟执行一次。

      IDS是英文“Intrusion Detection Systems”的缩写,中文意思是“入侵检测系统”。

      脚本内容

    第一个里程碑:生成md5验证文件

    文件的校验文件

    find /var/html/www/* -type f |xargs md5sum >/tmp/check/web_file_check.md5sum

    目录的校验文件

    tree /var/html/www/ -d  >/tmp/check/web_dir_check.txt
    md5sum /tmp/check/web_dir_check.txt
    md5sum /tmp/check/web_dir_check.txt >/tmp/check/web_dir_check.md5sum

    脚本内容

    入侵检测与报警

    1 [root@clsn check]# cat web_file_check.sh
    2 #!/bin/bash
    3 #############################################################
    4 # File Name: web_file_check.sh
    5 # Version: V1.0
    6 # Author: clsn
    7 # Organization: http://blog.znix.top
    8 # Created Time : 2017-12-10 14:15:34
    9 # Description:
    10 #############################################################
    11
    12 Url1=http://10.0.0.1/web_file_check.md5sum
    13 Url2=http://10.0.0.1/web_dir_check.md5sum
    14 Dir=/tmp/check/
    15 Web_Dir=/var/html/www/
    16 Check_File1=/tmp/check/web_file_check.md5sum
    17 Check_File2=/tmp/check/web_dir_check.md5sum
    18 Check_Dir=/tmp/check/web_dir_check.txt
    19 Check_Out=/tmp/check/check_out.md5sum
    20 Mail_info=/tmp/check/mail.txt
    21 Date=`date +%F_%T`
    22 Host_Name=`hostname`
    23 Host_IP=`hostname -I`
    24 Email_Addr=995701749@qq.com
    25
    26 [ -d $Dir ] || mkdir -p $Dir
    27 if [ ! -f $Check_File1 ]
    28   then
    29     cd $Dir &&\
    30     wget $Url1
    31 elif [ ! -f $Check_File2 ]
    32    then
    33     cd $Dir &&\
    34     wget $Url2
    35 fi
    36
    37 md5sum -c $Check_File1 >$Check_Out  2>/dev/null
    38 Back_num1=$?
    39 tree -d $Web_Dir >$Check_Dir
    40 md5sum -c $Check_File2 &>/dev/null
    41 Back_num2=$?
    42 if [ $Back_num1 -ne 0 ]
    43   then
    44     echo "发生主机:$Host_Name  主机IP地址:$Host_IP"  > $Mail_info
    45     echo "在 $Date 的检测中发现以下文件被篡改" >>$Mail_info
    46     echo "==================================================" >>$Mail_info 
    47     egrep  -i  "失败|failed"  $Check_Out >>$Mail_info
    48     echo "==================================================" >>$Mail_info 
    49     echo "请尽快登陆服务器进行处理!!!"  >>$Mail_info
    50     mail -s "【警告】web站点文件被篡改" -a $Check_File1 $Email_Addr <$Mail_info
    51 fi
    52
    53 if [ $Back_num2 -ne 0 ]
    54   then
    55     echo "目录检测信息" >$Mail_info
    56     echo "在 $Date 的检测中发现目录被篡改" >>$Mail_info
    57     mail -s "【警告】web站点目录被篡改" -a $Check_Dir $Email_Addr<$Check_Dir
    58 fi

    修改文件目录后执行结果

     

     

    3.9.5 【练习题5】单词及字母去重排序案例

    用shell处理以下内容

      1、按单词出现频率降序排序!

      2、按字母出现频率降序排序!

    the squid project provides a number ofresources to assist users design implement and support squid installations.Please browse the documentation and support sections for more infomation byoldboy training

             脚本内容:

    [root@clsn play]# cat abc.sh
    #!/bin/bash
    #############################################################
    # File Name: abc.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-11 17:23:19
    # Description:
    #############################################################

    a="the squid project provides a number ofresources to assist users design implement and support squid installations.Please browse the documentation and support sections for more infomation byoldboy training"

    echo "按单词出现频率降序排序!"
    for i in $a
      do
       echo $i
    done|\
      sort |uniq -c|sort -nk1  -r
    echo "按字母出现频率降序排序!"
    echo $a |grep -o "[a-z]" |sort|uniq  -c |sort -nk1 -r

    3.9.6 【练习题6】编写正(或长)方形图形案例

    请用shell或Python编写一个正(或长)方形,接收用户输入的数字。

             shell脚本内容

    [root@clsn play]# cat  zhengfangxing.sh
    #!/bin/bash
    #############################################################
    # File Name: zhengfangxing.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-11 17:33:33
    # Description:
    #############################################################
    trap "echo 输入exit退出" 2
    while true
      do
        read -p "你想看多大的正方形:" a
        [ "$a" == "exit" ] && exit
        expr 1 + $a &>/dev/null 
        [ $? -ne 0 ] && echo "请输入一个数字!" && exit 2
        b="■ "
        d=$(for i in `eval echo {1..$a}`;do echo -n $b; echo -n " ";done)
       
        for i in `eval echo {1..$a}`
         do
          echo "$d"
        done
    done

             脚本执行效果

    [root@clsn play]# sh  zhengfangxing.sh  4
    ■ ■ ■ ■
    ■ ■ ■ ■
    ■ ■ ■ ■
    ■ ■ ■ ■
    [root@clsn play]# sh  zhengfangxing.sh  3
    ■ ■ ■
    ■ ■ ■
    ■ ■ ■

    3.10 各种语句小结

      ?  while循环的特长是执行守护进程以及我们希望循环不退出持续执行,用于频率小于1分钟循环处理(crond),其他的while循环几乎都可以被for循环替代。

      ?   case语句可以被if语句替换,一般在系统启动脚本传入少量固定规则字符串用case语句,其他普通判断多用if。

      ?  一句话,if,for语句最常用,其次while(守护进程),case(服务启动脚本)。

    3.11 附录

    3.11.1 格式化文本--对齐文本

    [root@clsn scripts]# column --help

    用法:
    column [选项] [文件 ...]

    选项:
    -c, --columns <宽度>     输出宽度(字符数)
    -t, --table              创建表格
    -s, --separator <字符串> 可用的表格分隔符
    -o, --output-separator <字符串>
                              表格输出列分隔符,默认为两个空格
    -x, --fillrows           先填充行,再填充列

    -h, --help     显示此帮助并退出
    -V, --version  输出版本信息并退出

    更多信息请参阅 column(1)。

    3.11.2 服务器被挂马怎么办?

    1. 将被挂马服务器上,原有重要数据备份下来
    2. 仔细筛查数据,确保其中都是正常文件
    3. 重新安装服务器操作系统,并针对性的加强安全防护。
    4. 切记,服务器中木马后必须重新安装操作系统。

    3.11.3 怎么通过进程找到程序

    通过进程找到pid号码

    [root@clsn proc]# ps -ef |grep sshd
    root       1294      1  0 09:18 ?        00:00:00 /usr/sbin/sshd -D

             通过pid找到在proc目录下的临时文件夹

    [root@clsn proc]# cd /proc/1294
    [root@clsn 1294]#

             查看其中的exe文件,即可发现程序文件的路径

    [root@clsn 1294]# ll exe
    lrwxrwxrwx 1 root root 0 12月 11 09:18 exe -> /usr/sbin/sshd

    3.11.4 screen程序 防止脚本执行中断

      用操作,更多详情参照 http://www.cnblogs.com/clsn/p/8022625.html

    ctrl +a +d  退出当前终端,返回加载screen前的shell命令状态
    screen -ls 可看screen会话
    screen -r id 指定进入哪个screen会话

             screen进程原理

    [root@clsn ~]# ps -ef |grep ping
    root      30170  30153  0 11:57 pts/5    00:00:00 ping 10.0.0.254
    root      30172  30078  0 11:58 pts/0    00:00:00 grep --color=auto ping
    [root@clsn ~]# ps -ef |grep 30170
    root      30170  30153  0 11:57 pts/5    00:00:00 ping 10.0.0.254
    root      30174  30078  0 11:59 pts/0    00:00:00 grep --color=auto 30170
    [root@clsn ~]# ps -ef |grep 30153
    root      30153  30119  0 11:57 pts/5    00:00:00 /bin/bash
    root      30170  30153  0 11:57 pts/5    00:00:00 ping 10.0.0.254
    root      30176  30078  0 11:59 pts/0    00:00:00 grep --color=auto 30153
    [root@clsn ~]# ps -ef |grep 30119
    root      30119      1  0 11:56 ?        00:00:00 SCREEN
    root      30120  30119  0 11:56 pts/4    00:00:00 /bin/bash
    root      30153  30119  0 11:57 pts/5    00:00:00 /bin/bash
    root      30178  30078  0 11:59 pts/0    00:00:00 grep --color=auto 30119

    3.11.5 shell中实现倒计时效果

    脚本内容

    [root@clsn scripts]# cat daojishi.sh
    #!/bin/bash
    #############################################################
    # File Name: daojishi.sh
    # Version: V1.0
    # Author: clsn
    # Organization: http://blog.znix.top
    # Created Time : 2017-12-12 08:49:11
    # Description:
    #############################################################

    for i in `seq -w 10 -1 1`
      do
        echo -ne "\b\b$i";
        sleep 1;
    done

    脚本执行效果

     

    3.12 linux中的信号

    3.12.1 Linux系统的重要信号及说明

    信号

    说明

    HUP(l)

    挂起,通常因终端掉线或用户退出而引发

    INT(2)

    中断,通常因按下Ctrl+c组合键而引发

    QUIT(3)

    退出,通常因按下Ctrl+\组合键而引发

    ABRT(6)

    中止,通常因某些严重的执行错误而引发

    ALRM(14)

    报警,通常用来处理超时

    TERM(15)

    终止,通常在系统关机时发送

    TSTP(20)

    停止进程的运行,但该信号可以被处理和忽略,通常因按下Ctrl+z组合键而引发

       使用trap控制信号通常需要忽略的信号包括HUP、INT、QUIT、TSTP、TERM等,对应的信号编号分别为1、2、3、20、15。Shell脚本中既可以用数字来代表信号,也可以使用信号的名字来代表信号

    3.12.2使用trap控制信号

      trap命令用于指定在接收到信号后将要采取的行动,信号的相关说明前面已经提到 过。trap命令的一种常见用途是在脚本程序被中断时完成清理工作,或者屏蔽用户非法 使用的某些信号。在使用信号名时需要省略SIG前缀。可以在命令提示符下输人命令 trap -1来查看信号的编号及其关联的名称。

      trap命令的参数分为两部分,前一部分是接收到指定信号时将要采取的行动,后一部分是要处理的信号名。

      trap命令的使用语法如下:

    trap command signal

           signal是指接收到的信号,command是指接收到该信号应采取的行动。也就是:

    trap ‘命令;命令’ 信号编号

    trap ‘命令;命令’ 信号名

    [root@clsn ~]# trap 'echo clsn' 2
    [root@clsn ~]# ^Cclsn

    3.13 参考文档

    本篇博文整理自惨绿少年:

    https://www.cnblogs.com/clsn/

     

    展开全文
  • 70个经典的 Shell 脚本

    万次阅读 多人点赞 2018-08-30 13:45:58
    阿里Linux Shell脚本面试25个经典问答 分享70个经典的 Shell 脚本面试题与答案     1) 如何向脚本传递参数 ? ./script argument 例子: 显示文件名称脚本 ? 1 2 3 4 ./show.sh ...

    参考:

    1. 阿里Linux Shell脚本面试25个经典问答
    2. 分享70个经典的 Shell 脚本面试题与答案

     

     

    1) 如何向脚本传递参数 ?

    ./script argument

    例子: 显示文件名称脚本

    ?

    1

    2

    3

    4

    ./show.sh file1.txt

    cat show.sh

    #!/bin/bash

    echo $1

    (LCTT 译注:谢谢某匿名访客的提醒,原题有误,修改之。)

    2) 如何在脚本中使用参数 ?

    第一个参数 : $1,第二个参数 : $2

    例子 : 脚本会复制文件(arg1) 到目标地址(arg2)

    ?

    1

    2

    3

    4

    ./copy.sh file1.txt /tmp/

    cat copy.sh

    #!/bin/bash

    cp $1 $2

    3) 如何计算传递进来的参数 ?

    $#

    4) 如何在脚本中获取脚本名称 ?

    $0

    5) 如何检查之前的命令是否运行成功 ?

    $?

    6) 如何获取文件的最后一行 ?

    tail-1

    7) 如何获取文件的第一行 ?

    head-1

    8) 如何获取一个文件每一行的第三个元素 ?

    awk'{print $3}'

    9) 假如文件中每行第一个元素是 FIND,如何获取第二个元素

    awk'{ if ($1 == "FIND") print $2}'

    10) 如何调试 bash 脚本

    -xv 参数加到 #!/bin/bash

    例子:

    #!/bin/bash –xv

    11) 举例如何写一个函数 ?

    ?

    1

    2

    3

    function example {

    echo "Hello world!"

    }

    12) 如何向连接两个字符串 ?

    ?

    1

    2

    3

    4

    V1="Hello"

    V2="World"

    V3=${V1}${V2}

    echo $V3

    输出

    HelloWorld

    13) 如何进行两个整数相加 ?

    ?

    1

    2

    3

    4

    V1=1

    V2=2

    let V3=$V1+$V2

    echo $V3

    输出

    3

    据 @kashu 的意见,本题的更佳回答为:

    两个整数相加,还有若干种方法实现:

    ?

    1

    2

    3

    4

    5

    6

    7

    A=5

    B=6

    echo $(($A+$B)) # 方法 2

    echo $[$A+$B]  # 方法 3

    expr $A + $B   # 方法 4

    echo $A+$B | bc # 方法 5

    awk 'BEGIN{print '"$A"'+'"$B"'}'  # 方法 6

    14) 如何检查文件系统中是否存在某个文件 ?

    ?

    1

    2

    3

    4

    if [ -f /var/log/messages ]

    then

    echo "File exists"

    fi

    15) 写出 shell 脚本中所有循环语法 ?

    for 循环 :

    ?

    1

    2

    3

    foriin$(ls);do

    echo item:$i

    done

    while 循环 :

    ?

    1

    2

    3

    4

    5

    6

    #!/bin/bash

    COUNTER=0

    while [ $COUNTER -lt 10 ]; do

    echo The counter is $COUNTER

    let COUNTER=COUNTER+1

    done

    until 循环 :

    ?

    1

    2

    3

    4

    5

    6

    #!/bin/bash

    COUNTER=20

    until [ $COUNTER -lt 10 ]; do

    echo COUNTER $COUNTER

    let COUNTER-=1

    done

    16) 每个脚本开始的 #!/bin/sh#!/bin/bash 表示什么意思 ?

    这一行说明要使用的 shell#!/bin/bash 表示脚本使用 /bin/bash。对于 python 脚本,就是

    #!/usr/bin/python

    17) 如何获取文本文件的第 10 行 ?

    head -10 file|tail -1

    18) bash 脚本文件的第一个符号是什么

    #

    19) 命令:[ -z "" ] && echo 0 || echo 1 的输出是什么

    0

    20) 命令 “export” 有什么用 ?

    使变量在子 shell 中可用。

    21) 如何在后台运行脚本 ?

    在脚本后面添加 “&”

    据 @kashu 的意见,更好的答案是:

    nohup command&

    大部分时间我们可能是远程使用Linux,我碰到过由于网络断线使得在后台运行的command &没了...

    22) "chmod 500 script" 做什么 ?

    使脚本所有者拥有可执行权限。

    23) ">" 做什么 ?

    重定向输出流到文件或另一个流。

    24) &&& 有什么区别

    • & - 希望脚本在后台运行的时候使用它
    • && - 当前一个脚本成功完成才执行后面的命令/脚本的时候使用它

    25) 什么时候要在 [ condition ] 之前使用 “if” ?

    当条件满足时需要运行多条命令的时候。

    26) 命令: name=John && echo 'My name is $name' 的输出是什么

    variable

    27) bash shell 脚本中哪个符号用于注释 ?

    #

    28) 命令: echo ${new:-variable} 的输出是什么

    variable

    29) '" 引号有什么区别 ?

    • ' - 当我们不希望把变量转换为值的时候使用它。
    • " - 会计算所有变量的值并用值代替。

    30) 如何在脚本文件中重定向标准输出和标准错误流到 log.txt 文件 ?

    在脚本文件中添加 "exec >log.txt 2>&1" 命令。

    31) 如何只用 echo 命令获取字符串变量的一部分 ?

    ?

    1

    2

    3

    echo ${variable:x:y}

    x - 起始位置

    y - 长度

    例子:

    ?

    1

    2

    variable="My name is Petras, and I am developer."

    echo ${variable:11:6} # 会显示 Petras

     

    32) 如果给定字符串 variable="User:123:321:/home/dir",如何只用 echo 命令获取 home_dir ?

    echo ${variable#*:*:*:}

    echo ${variable##*:}

    33) 如何从上面的字符串中获取 “User” ?

    echo ${variable%:*:*:*}

    echo ${variable%%:*}

    34) 如何使用 awk 列出 UID 小于 100 的用户 ?

    awk -F: '$3<100' /etc/passwd

    35) 写程序为用户计算主组数目并显示次数和组名

    ?

    1

    2

    3

    4

    cat /etc/passwd|cut -d: -f4|sort|uniq -c|while read c g

    do

    { echo $c; grep :$g: /etc/group|cut -d: -f1;}|xargs -n 2

    done

    36) 如何在 bash shell 中更改标准的域分隔符为 ":" ?

    IFS=":"

    37) 如何获取变量长度 ?

    ${#variable}

    38) 如何打印变量的最后 5 个字符 ?

    echo ${variable: -5}

    39) ${variable:-10}${variable: -10} 有什么区别?

    • ${variable:-10} - 如果之前没有给 variable 赋值则输出 10;如果有赋值则输出该变量
    • ${variable: -10} - 输出 variable 的最后 10 个字符

    40) 如何只用 echo 命令替换字符串的一部分 ?

    echo ${variable//pattern/replacement}

    41) 哪个命令将命令替换为大写 ?

    tr '[:lower:]' '[:upper:]'

    42) 如何计算本地用户数目 ?

    wc -l /etc/passwd|cut -d" " -f1 或者 cat /etc/passwd|wc -l

    43) 不用 wc 命令如何计算字符串中的单词数目 ?

    ?

    1

    2

    set ${string}

    echo $#

    44) "export $variable""export variable" 哪个正确 ?

    export variable

    45) 如何列出第二个字母是 a 或 b 的文件 ?

    ls -d ?[ab]*

    46) 如何将整数 a 加到 b 并赋值给 c ?

    c=$((a+b))

    c=`expr $a + $b`

    c=`echo "$a+$b"|bc`

    47) 如何去除字符串中的所有空格 ?

    echo $string|tr -d " "

    48) 重写这个命令,将输出变量转换为复数: item="car"; echo "I like $item" ?

    item="car"; echo "I like ${item}s"

    49) 写出输出数字 0 到 100 中 3 的倍数(0 3 6 9 …)的命令 ?

    for i in {0..100..3}; do echo $i; done

    for (( i=0; i<=100; i=i+3 )); do echo "Welcome $i times"; done

    50) 如何打印传递给脚本的所有参数 ?

    echo $*

    echo $@

    51) [ $a == $b ][ $a -eq $b ] 有什么区别

    • [ $a == $b ] - 用于字符串比较
    • [ $a -eq $b ] - 用于数字比较

    52) === 有什么区别

    • = - 用于为变量赋值
    • == - 用于字符串比较

    53) 写出测试 $a 是否大于 12 的命令 ?

    [ $a -gt 12 ]

    54) 写出测试 $b 是否小于等于 12 的命令 ?

    [ $b -le 12 ]

    55) 如何检查字符串是否以字母 "abc" 开头 ?

    [[ $string == abc* ]]

    56) [[ $string == abc* ]][[ $string == "abc*" ]] 有什么区别

    • [[ $string == abc* ]] - 检查字符串是否以字母 abc 开头
    • [[ $string == "abc" ]] - 检查字符串是否完全等于 abc

    57) 如何列出以 abxy 开头的用户名 ?

    egrep "^ab|^xy" /etc/passwd|cut -d: -f1

    58) bash 中 $! 表示什么意思 ?

    后台最近执行命令的 PID.

    59) $? 表示什么意思 ?

    前台最近命令的结束状态。

    60) 如何输出当前 shellPID ?

    echo $$

    61) 如何获取传递给脚本的参数数目 ?

    echo $#

    (LCTT 译注:和第3题重复了。)

    *62) $*$@ 有什么区别*

    • $* - 以一个字符串形式输出所有传递到脚本的参数
    • $@ - 以 $IFS 为分隔符列出所有传递到脚本中的参数

    63) 如何在 bash 中定义数组 ?

    array=("Hi" "my" "name" "is")

    64) 如何打印数组的第一个元素 ?

    echo ${array[0]}

    65) 如何打印数组的所有元素 ?

    echo ${array[@]}

    66) 如何输出所有数组索引 ?

    echo ${!array[@]}

    67) 如何移除数组中索引为 2 的元素 ?

    unset array[2]

    68) 如何在数组中添加 id 为 333 的元素 ?

    array[333]="New_element"

    69) shell 脚本如何获取输入的值 ?

    a) 通过参数

    ./script param1 param2

    b) 通过 read 命令

    read -p "Destination backup Server : " desthost

    70) 在脚本中如何使用 "expect" ?

    ?

    1

    2

    3

    4

    5

    6

    /usr/bin/expect << EOD

    spawn rsync -ar ${line} ${desthost}:${destpath}

    expect "*?assword:*"

    send "${password}\r"

    expect eof

    EOD

    展开全文
  • Shell脚本编写实战

    千人学习 2019-06-26 12:12:05
    根据实际的案例讲解怎么编写Shell脚本,在什么场景下编写为讲解导向。 课程内容如下: 1.编写Shell脚本注意事项与编写打印字体颜色函数 2.批量创建用户 3.监控主机存活状态 4.监控CPU、内存、硬盘和网卡流量...
  • shell脚本精简教程

    万人学习 2018-10-22 21:38:06
    详细的介绍shell脚本的使用。
  • 脚本的编写 这里写代码片

    一. shell 脚本中的基本知识

    1.什么是 shell

    shell 是操作系统中的一个软件。它包在 linux 内核的外面,为用户和内核之间的
    交互提供了一个接口,系统中的命令用 shell 去解释shell 接收系统回应的输出并
    显示其到屏幕中。

    二.脚本的编写

    shell脚本

    1.什么是shell脚本

    脚本是一种解释型语言。用shell脚本保存执行动作;用脚本判定命令的执行条件;用脚本来实现动作的批量执行。

    三.如何创建shell脚本

    vim script.sh     用 vim 编写脚本
    #!/bin/bash       脚本使用的解释器,通常用幻数 "#!" 指定
    #AUTHOR           脚本作者
    #DATE             脚本创作时间
    #MAIL             脚本作者联系方式
    #VERSION          脚本的版本

    四.脚本的编写

    1)编写脚本

    1.cd /mnt/ 进入目录

    2.vim westos.sh 编辑脚本

    这里写图片描述

    内容:

    #!/bin/bash    幻数(执行脚本调用的解释器)
    watch -n 1 date

    这里写图片描述

    2)执行脚本有两种方法:

    1.sh westos.sh 执行脚本

    这里写图片描述

    执行结果:

    这里写图片描述

    2.chmod +x westos.sh 加可执行权限

    /mnt/westos.sh 绝对路径的方式执行

    这里写图片描述

    执行结果:

    这里写图片描述

    3)脚本调试:

    编辑脚本:vim westos.sh

    内容:

    #! /bin/bash -xecho  
    hello westos

    这里写图片描述

    用绝对路径执行后会显示执行脚本调用的解释器和执行结果

    ## + echo hello westos 执行脚本调用的解释器 ##
    ## hello westos 执行结果 ##
    这里写图片描述

    编辑脚本自动添加标题:

    1. vim /etc/vimrc 编辑vim配置文件

    内容:

    67 autocmd BufNewFile *.sh exec ":call WESTOS()"   打开以.sh结尾
    的新的文件会自动添加
     68 " map <F4> ms:call WESTOS()<cr>'s   打开文件按F4会自动添加标题
     69
     70 function WESTOS()
     71      call append(0,"#####################################")
     72      call append(1,"# Author : lee                      #")
     73      call append(2,"# Mail : lee@westos.com             #")
     74      call append(3,"# Viersion : 1.0                    #")
     75      call append(4,"# Create_Time : ".strftime("%Y-%m-%d")."          #")
     76      call append(5,"# Description :                     #")
     77      call append(6,"#                                   #")
     78      call append(7,"#                                   #")
     79      call append(8,"#####################################")
     80      call append(9,"")
     81      call append(10,"#!/bin/bash")
     82 endfunction

    这里写图片描述

    执行结果:vim file.sh

    这里写图片描述

    脚本示例:编辑脚本显示ip

    1.vim ip_show.sh 编辑脚本显示ip

    内容:

    #####################################
    # Author : lee                      #
    # Mail : lee@westos.com             #
    # Viersion : 1.0                    #
    # Create_Time : 2018-05-14          #
    # Description :                     #
    #                                   #
    #                                   #
    #####################################
    
    #!/bin/bash
    ifconfig eth0 | awk -F " " '/inet /{print $2}'   显示ip

    这里写图片描述

    2.sh ip_show.sh 执行

    这里写图片描述

    编辑脚本显示主机用户:

    1.vim use_show.sh 编辑脚本

    内容:

    #####################################
    # Author : lee                      #
    # Mail : lee@westos.com             #
    # Viersion : 1.0                    #
    # Create_Time : 2018-05-09          #
    # Description :                     #
    #                                   #
    #                                   #
    #####################################
    
    #!/bin/bash
    awk -F : '/bash$/{print $1}' /etc/passwd

    这里写图片描述

    2.sh use_show.sh 执行脚本

    这里写图片描述

    五.脚本命令

    diff           比较两文件的不同
    uniq           对重复字符做相应的处理,uniq配合sort用
    patch          打补丁
    tr             字符转换(文件内容)
    cut            字符截取
    test           和[]等同
    sort           字符排列
    &&和||         是与非,&& 用来执行条件成立后执行命令。
                          || 用来执行条件不成立后执行命令。 

    1. diff 比较两文件的不同

    diff在比较文件过程中结果读取方式:

    [num1,num2]a|c|d[num3,num4]
    num1,num2表示在第一个文件的行数
    a表示添加:add 
    c表示更改:change
    d表示删除:delete
    num3,num4 表示在第二个文件中的行数

    示例:

    1.cd /mnt                  进入目录建立文件
    2.vim westos :123         建立文件westos写入内容:123
      vim westos1 : 123       建立文件westos1写入内容:123            
                     456                              456
    用diff比较两个的文件的不同:表示第一个文件的第二行在加上456就和第二个文件一样。

    这里写图片描述

    打补丁:

    1.yum  install patch -y                  安装打补丁软件
    2.diff   -u  westos westos1 > file.path  生成补丁文件
    3.patch westos  file.path                打补丁(会覆盖源文件内容)
    4.patch -b westos file.path              打补丁不会覆盖源件
    file.path     westos      westos1  westos.orig
    补丁文件     打补丁后的文件    原文件    原文件
    5.patch -r dir1 dir2                     比较两个目录的不同

    这里写图片描述

    2. cut 用于字符截取

    cut -d              指定分隔符
    cut -f 1,7|1-7     指定截取的列
    cut -c 1,4|1-4     指定截取的字符位置

    3. sort 用于字符排列

    sort -n       纯数字排列
    sort -r       倒序
    sort -u       去掉重复数字
    sort -o       输出到指定文件中
    sort -t       指定分隔符
    sort -k       指定排序的列

    示例:ls -l /mnt/ | sort -t ” ” -k 5 -n

    这里写图片描述

    4.uniq 对重复字符做相应的处理,uniq配合sort用

    uniq       对重复字符做相应的处理
    uniq -u    显示唯一的行
    uniq -d    显示重复的行
    uniq -c    每行显示一次并统计重复次数

    示例:

    vim   hello     编辑文件写入内容:

    这里写图片描述

    处理结果:

    这里写图片描述

    5. &&和|| 是与非。

    && 用来执行条件成立后执行命令。

    || 用来执行条件不成立后执行命令。

    示例: vim check_ip.sh 编辑脚本ping “IP”通的显示up不通显示down

    内容:
    #####################################
    # Author : lee                      #
    # Mail : lee@westos.com             #
    # Viersion : 1.0                    #
    # Create_Time : 2018-05-09          #
    # Description :                     #
    #                                   #
    #                                   #
    #####################################
    
    #!/bin/bash
    
    ping -c1 -w1 $1 &>/dev/null   && echo $1 is up   || echo $1 is down

    这里写图片描述

    执行结果:

    这里写图片描述

    6.test 和[ ]等同

    test "$A"="$B"      等同 ["$A"="$B"]
    ["$A"="$B"]         表示"$A"="$B"成立
    ["$A"!="$B"]       表示"$A"="$B"不成立
    [ -z "$A"]          表示$A是否为空
    [ -n "$A"]          表示$A是否不为空  

    示例:

    这里写图片描述

    整型数据比较:

    参数:
    -eq   等于
    -ne   不等于
    -le   小于等于
    -lt   小于
    -ge   大于等于
    -gt   大于

    示例:

    a=10      给a赋值
    b=20      给b赋值
    [ "$a" -eq "$b" ] && echo yes || echo no  $a等于$b成立输出yes不成立输出no
    [ "$a" -ne "$b" ] && echo yes || echo no  $a不等于$b成立输出yes不成立输出no
    [ "$a" -le "$b" ] && echo yes || echo no  $a小于等于$b成立输出yes不成立输出no
    [ "$a" -lt "$b" ] && echo yes || echo no  $a小于$b成立输出yes不成立输出no
    [ "$a" -ge "$b" ] && echo yes || echo no  $a大于等于$b成立输出yes不成立输出no
    [ "$a" -gt "$b" ] && echo yes || echo no  $a大于$b成立输出yes不成立输出no

    这里写图片描述

    [ "$a" = "$b" -o "$a" -lt "50" ] $a是否等于$b,或者$a小于50
    [ "$a" = "$b" -a "$a" -lt "50" ] $a是否等于$b,并且$a小于50
    -o   表示或者
    -a   表示并且

    示例:

    这里写图片描述

    编辑脚本:vim check_num.sh   判定一个数字是否在0-10之间,脚本后面没数字显示please give me a number!,有数字进行判定在1-10输出yes否则输出no。
    #!/bin/bash
    [ -z "$1" ] && {         判定脚本后第一穿字符是否为空
           echo please give me a number !!
           exit  1
    }
    [ "$1"  -gt "0" -a "$1"  -lt "10" ]    && echo  yes || echo  no

    这里写图片描述

    执行结果:

    这里写图片描述

    示例:

    编辑脚本:vim clean_log.sh  清空日志,如果不是超级用户输出您不是超级用户!,如果是超级用户执行清空日志
    内容:
    #!/bin/bash
    User_ID=`id -u`       变量
    [ "$User_ID" -ne "0" ] && {     uid不等于0
           echo      您不是超级用户!
           exit 1
    }
    > /var/log/messages

    这里写图片描述

    执行结果:

    这里写图片描述

    文件比较:

    [ "file1"  -ef "file" ]  节点是否一致,即文件是否一样 
    [ "file1"  -ef "file" ]   file1是否比file2时间新
    [ "file1"  -ef "file" ]   file1是否比file2时间老

    示例:

    touch  linux                   建立文件
    ls -i linux                    查看文件节点号
    ln  /mnt/linux /mnt/linux1     创建硬链接
    ls -i /mnt/linux /mnt/linux1   查看硬链接两个文件的节点号

    这里写图片描述

    判断结果:

    [ "/mnt/linux" -ef "/mnt/linux1" ] && echo yes || echo no  
    判断两个文件节点号是否一致
    [ "/mnt/linux" -nt "/mnt/passwd" ] && echo yes || echo no  
    判断linux文件是否比passwd文件新出现
    [ "/mnt/linux" -ot "/mnt/passwd" ] && echo yes || echo no  
    判断linux文件是否比passwd文件早

    这里写图片描述

    test命令:判定文件的类型

    参数:
    [ -e "file" ]    文件是否存在
    [ -f "file" ]    文件是否为普通文件
    [ -L "file" ]    文件时否为连接(软连接)
    [ -S "file" ]    文件是否为套接字
    [ -b "file" ]    文件是否为快设备
    [ -d "file" ]    文件是否为目录
    [ -c "file" ]    文件是否为字符设备
    ln -S /mnt/file  /mnt/hello    创建链接-s表示软链接,不加-s表示硬链接

    示例:

    编写脚本:vim   file.sh    判定文件是什么类型的文件
    内容:
    #!/bin/bash
    [ -z "$1" ] && {          脚本后是否为空
           echo please give me a filename !!   为空输出please give me a filename !!
           exit 1
    }
    [ -e $1 ] || {                文件是否存在
        echo $1 is not file       文件不存在
    }
    [ -L $1 ] && {                文件是否为连接
        echo $1 is a link file    文件是连接
        exit 1
    }
    [ -f $1 ] && {                 文件是否为普通文件
        echo $1 is a common file   文件是普通文件
    }
    [ -S $1 ] && {                 文件是否为套接字
       echo $1 is a sock file      文件是套接字
    }

    这里写图片描述

    执行结果:

    这里写图片描述

    7. tr 字符转换(文件内容)

    tr 'a-z' 'A-Z'  < /mnt/westos   > /mnt/hello    
    将westox内容转化成大写并重定向到/mnt/hello中

    示例:

    这里写图片描述

    8.find 查找

    参数:
    -type          类型
    -size          大小
    -perm          权限
    -user          拥有着
    -group         所有组
    -name          名字
    -mindepth      最小深度
    -maxdepth      最大深度

    示例:

    find /mnt/ -type l          查找/mnt/的连接的文件
    find /mnt/ -group student   查找/mnt/的student组的文件
    find  /mnt/ -user root -a  -group student   
    查找/mnt/的文件是root用户并且是student组的文件
    find  /mnt/ -user root -o  -group student   
    查找/mnt/的文件是root用户或者是student组的文件

    这里写图片描述

    find /mnt/ -perm            权限查找
    例如:
    find /mnt/ -perm   444      权限查找(查找/mnt下权限为444的文件)
    find /mnt/ -perm /444       权限查找(u位有4或者g位有4或者o位有4) /表示或者
    find /mnt/ -perm -444       权限查找(u位有4并且g位有4并且o位有4) -表示并且

    这里写图片描述

    find /mnt/  -size     文件的大小查找
    示例:
    dd if=/dev/zero of=/mnt/file1 bs=1024 count=10     截取文件
    dd if=/dev/zero of=/mnt/file2 bs=1024 count=20     截取文件
    dd if=/dev/zero of=/mnt/file3 bs=1024 count=30     截取文件
    find /mnt/ -size 20k       查找大小为20k的文件
    find /mnt/ -size -20k      查找大小小于20k的文件
    find /mnt/ +size -20k      查找大小大于20k的文件

    这里写图片描述

    find /etc -maxdepth    深度查找
    find /etc -maxdepth 1 -name passwd    查找深度位1的文件
    find /etc -mindepth 1 -maxdepth 2 -name passwd    
    查找最小深度位1最大深度位2的文件

    这里写图片描述

    展开全文
  • Shell脚本(一)

    万次阅读 多人点赞 2019-08-04 12:02:48
    20.1 什么是Shell脚本 shell脚本并不能作为正式的编程语言,因为它是在linux的shell中运行的,所以称为shell脚本。事实上,shell脚本就是一些命令的集合。 假如完成某个需求需要一口气输入10条命令,对于简单的命令...
  • shell脚本之工具

    万次阅读 2018-07-12 16:10:02
    在学习了shell脚本的基本语法,命令,符号之后,接下来要看的就是shell脚本使用的所有工具了。 在shell脚本中,工具的使用简化了所要编写的代码。接下来就介绍几个shell下经常使用的工具。 1、sort sort工具的...
  • shell脚本语法

    万次阅读 2019-06-01 11:07:39
    shell脚本基本语法 默认一行处理一条命令,但也可以用;分割多条命令,按顺序执行。 脚本文件中第一行必须用#! path-to-shell指定所用的shell。 除了第一行之外的#都是注释的开始标记,注释此行中#之后的...
  • Linux中编写Shell脚本

    万次阅读 多人点赞 2020-02-04 17:02:12
    Shell脚本的执行 Shell脚本编写规范 Shell 中的变量 变量的算术运算 双小括号 (()) 数值运算命令的用法 let 运算命令的用法 expr 命令的用法 br 命令的用法 $[]符号的运算示例 Shell脚本的条件测试 几种...
  • 常用shell脚本

    万次阅读 多人点赞 2019-03-01 16:27:33
    脚本1】打印形状 打印等腰三角形、直角三角形、倒直角三角形、菱形 #!/bin/bash # 等腰三角形 read -p "Please input the length: " n for i in `seq 1 $n` do for ((j=$n;j&gt;i;j--)) do ...
  • 一些简单的shell脚本实例

    千次阅读 多人点赞 2020-03-13 23:47:17
    # 脚本生成一个 100 以内的随机数,提示用户猜数字,根据用户的输入,提示用户猜对了, # 猜小了或猜大了,直至用户猜对脚本结束。 # RANDOM 为系统自带的系统变量,值为 0‐32767的随机数 # 使用取余算法将随机数变为 1...
  • shell脚本基本语法详解

    万次阅读 多人点赞 2019-11-16 17:22:43
    编写shell脚本的时候,最前面要加上一行:#!/bin/bash,因为linux里面不仅仅只有bash一个解析器,还有其它的,它们之间的语法会有一些不同,所以最好加上这一句话,告诉系统要用这个解析器。一.shell变量shell变量和...
  • shell脚本的作用,第一个shell脚本shell脚本的变量,shell给定的特殊变量,shell脚本的三种赋值方式
  • shell脚本编写思路和实例讲解

    万次阅读 多人点赞 2017-06-11 16:06:44
    shell脚本编写思路和实例讲解前言 常听见身边有很多学习shell脚本的朋友抱怨shell脚本不好写,好不容易写出来的脚本一直报错,符号空格又太多,错了一个就无法运行还不好排查错误。 客观讲shell脚本的简洁程度...
  • shell脚本返回值及其使用场景

    万次阅读 2018-01-05 10:59:44
    在一些应用中(比如Jenkins),嵌入了shell脚本,系统通过shell脚本的返回值来判断执行结果,如果返回值非0,则发生了执行错误,需要中止执行,这在使用单个命令时没有问题。然而,在shell (A)脚本又调用了shell...
  • 快速入门shell脚本编写(一)

    万次阅读 2015-01-28 20:05:00
    所以,今天就抽出一些时间学习学习Shell脚本。 shell有两种执行命令的方式: 交互式(Interactive):解释执行用户的命令,用户输入一条命令,Shell就解释执行一条。 批处理(Batch):用户事先写一个Shell脚本...
  • Shell脚本书写方法详解

    万次阅读 2018-05-31 12:04:02
    同学给我推荐了一个关于如何书写shell脚本教程文件。看过之后觉得受益良多,自己特意将该PDF内的内容自己总结了一份,在这里和大家分享一下。愿所有像我一样的shell脚本的初学者能够从中受益,少走弯路。首先,shell...
  • shell脚本基本语法

    千次阅读 2018-08-24 18:06:59
    终于到shell 脚本这章了,在以前笔者卖了好多关子说shell脚本怎么怎么重要,确实shell脚本在linux系统管理员的运维工作中非常非常重要。下面笔者就带你正式进入shell脚本的世界吧。 到现在为止,你明白什么是shell...
  • perl 、shell、python之shell脚本入门

    万次阅读 2014-07-23 15:37:05
    终于到shell 脚本这章了,在以前笔者卖了好多关子说shell脚本怎么怎么重要,确实shell脚本在linux系统管理员的运维工作中非常非常重要。下面笔者就带你正式进入shell脚本的世界吧。 到现在为止,你明白什么是shell...
1 2 3 4 5 ... 20
收藏数 421,820
精华内容 168,728
关键字:

shell脚本