Shell脚本介绍(资源)

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

导语 : 在Linux环境下,我们一般通过Shell来与内核交流,并最终实现我们想要使用计算机资源的目的。由于Linux的开放性特点,使得在Linux下对Shell的选择也很多,CentOS 6.3系统中可以使用的Shell有/bin/sh、/bin/bash、/bin/tcsh、/bin/csh这几种,/etc/shells文件说明了当前系统有哪些可用的Shell。不同的Shell有不同的特点以及操作方式,我们这里以CentOS默认使用的Shell为讲解案例即Bash。

     Linux下使用Shell处理文本时最常用的工具:

      CentOS 6.3默认通过/etc/profile文件定义了HISTSIZE=1000,也就是最多可以记录最近所使用的1000条命令,当有第1001条命令执行时第一条命令会被覆盖,执行history -c命令可以清空所有的历史记录。

      记录命令历史的除了可以查看历史记录外,还可以在需要时直接调用历史记录再次执行该命令:

     1.上下键翻阅历史命令,找到合适的命令后直接回车即可执行。

     2. 输入!string调用命令历史(string为关键字),如!vim将调用最后一次执行的以vim开头的命令。或者通过!n来准确定位历史记录,如!242将直接调用命令历史的第242条记录并执行。

      3. 通过Ctrl+r快捷键打开搜索功能,接着输入关键字即可在命令历史中搜索相关命令,回车完成执行操作。如果没有搜索到适合的命令按ESC键退出搜索

        标准输入的文件描述符为0,标准输出的文件描述符为1,错误输出的文件描述符为2。但有时我们需要改变这样的标准输入与输出方式,Linux中我们可以使用重定向符(<、>、<<、>>、|)重新定义输入与输出。

       管道符|的使用案例,使用ifconfig eth0 | grep ‘inet addr’命令过滤包含IP地址的行,ifconfig本身会输出大量网络接口的信息,由于这里使用了管道符号(|)所以ifconfig命令的所有输出都将作为grep命令的输入内容,最终实现过滤包含IP地址的行。

      以下通过几个简单的实例演示重定向的使用方法:

Shell脚本介绍(资源)_第1张图片

Bash快捷键

Shell脚本介绍(资源)_第2张图片

花括号{}的使用

Shell脚本介绍(资源)_第3张图片

 

一、SHELL编程概念

1)SHELL、SHELL编程、SHELL脚本、SHELL命令区别

Shell命令解释器,是用户和操作系统沟通的桥梁;

Shell编程,基于Shell解释器实现软件自动化功能;

Shell编程语言是非类型的解释型语言。

SHELL脚本,实现Shell编程实体;

SHELL命令,具体实现某个功能、内容的指令;

SHELL变量两种:局部变量和环境变量,赋值符号=,使用$符号引用

SHELL编程变量三种:系统变量、环境变量、用户变量

shel脚本变量类型  :  局部变量、环境变量、shell变量

元字符通常在Linux中分为两类  : 

  1. Shell元字符,由Linux Shell进行解析;

  2. 正则表达式元字符,由vi/grep/sed/awk等文本处理工具进行解析;

SHELL种类         : sh/dash/bash/ash/zsh

SHELL  配制文件  : ~/.bashrc  ,    .bash_profile    ,   .environmnet   

查询当前shell下的进程   :           ps -o pid,ppid,cmd'

Bash两种工作模式   : 互动模式  、Shell Script模式

互动模式  :     系统管理员由键盘键入命令,必须等待shell执行该命令之后,才能继续执行下一个命令。

Shell Script模式    : 管理这可以设计shell script ,把要执行的命令写在一个文件中,交友Bash去读取和执行。

bash变量类型环境变量、本地变量(局部变量)、位置变量、特殊变量;

本地变量 :VARNAME=VALUE :作用域为整个bash进程;

局部变量 : local VARNAME=VALUE : 作用域为当前代码段;

环境变量 :作用域为当前shell进程及其子进程;

export VARNAME=VALUE

VARNAME=VALUE

export VARNAME

         "导出"

位置变量 :$1,$2........

注意  :使用chsh命令可以改变默认的shell。

# chsh <用户名> -s <新shell>
# chsh linuxtechi -s /bin/sh

特殊变量 :

$? : 上一个命令的执行状态返回值;

*  :  代表任意的字符串,可以是空字符串
?  :  代表一个字符,单不可以为空

$# :计算传递进来的参数

$0 : 在脚本中获取脚本名称

$? : 检查之前的命令是否运行成功 

tail-1 : 获取文件的最后一行

head-1 : 获取文件的第一行 

awk'{print $3}' : 获取一个文件每一行的第三个元素

awk'{ if ($1 == "FIND") print $2}'  :文件中每行第一个元素是 FIND,如何获取第二个元素

调试 bash 脚本

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

例子:

#!/bin/bash –xv

 

程序执行 :可能有两类返回值;

         程序执行结果;

         程序状态码返回代码(0-255)

                    0:正确执行

                    1-255 : 错误执行,1,2,127系统预留;

输出重定向 :

    >        

   >>        

   2>       

   2>>     

   &>        

撤销变量

    unset VARNAME

查看当shell中变量

     set

查看当前shell中的环境变量

     printenv

     env

     export

脚本 : 命令的堆砌,按实际需要,结合命令流程控制机制实现的源程序。

在大多数Linux和其他类Unix系统上,默认的shell是Bash。

SHELL>SHELL编程>SHELL脚本>SHELL命令关系

SHELL编程变量定义存储到内存中,除非你的SHELL终端断开,否则一直长存内存缓冲区,变量名称不能使用特殊符号,变量名称之间不能使用-横杠,可以使用_下划线;

SHELL编程变量,变量名和变量值中间使用=,不能使用空格,SHELL变量用途主要减少重复去调用,化复杂为简单,化简单为自动化;

SHELL编程思想,通过手工操作的Linux/SHELL命令进行堆积;

脚本在执行时会启动一个子shell进程:

        命令行中启动的脚本会继承当前 shell环境变量;

        系统自动执行的脚本(非命令启动)就需要自定义需要各环境变量;

Shell的工作原理

Shell可以被称作是脚本语言,因为它本身是不需要编译的,而是通过解释器解释之后再编译执行,和传统语言相比多了解释的过程所以效率会略差于传统的直接编译的语言。

注意事项

1)开头加解释器:#!/bin/bash

2)语法缩进,使用四个空格;多加注释说明。

3)命名建议规则:变量名大写、局部变量小写,函数名小写,名字体现出实际作用。

4)默认变量是全局的,在函数中变量local指定为局部变量,避免污染其他作用域。

5)有两个命令能帮助我调试脚本:set -e 遇到执行非0时退出脚本,set-x 打印执行过程。  

6)写脚本一定先测试再到生产上。

 SHELL和SHELL编程概念

1) SHELL,SHELL是一款命令解释器,用户可以输入指令,传递给SHELL,SHELL指令传递到Linux内核,Linux内核处理数据,处理完毕之后将数据返回给SHELL,需要经过SHELL解释,解释完毕之后将最终的数据返回给用户;

2) SHELL是一个中间件,位于用户和Linux内核之间的,是用户和Linux内核的沟通桥梁;

3) SHELL是中间件,可以看成是一款软件,软件的种类:

4) SHELL编程,基于SHELL解释器执行的各种指令和代码,从而实现各种需求;

5) SHELL编程的产物是SHELL脚本,脚本文件,脚本文件中写入单个或者多个Linux指令,以实现某个具体的功能;

6)bash的配置文件

                profile类 : 登录式shell  

                bashrc类 : 非登录式shell

               登录式shell : /etc/profile-->/etc/profile.d/*.sh-->~/.bash_profile-->/.bashrc--->/etc/bashrc

               非登录式shell :~/.bashrc-->/etc/bashrc-->/etc/profile.d/*.sh

SHELL编程开始&编程规范

1) 任何的编程语言开始以打印世界,你好,表示开启新的一天;

2) 创建普通文件的指令:touch、vi、vim、cat、echo、mv、cp等;

3) 基于编程工具:vi、vim、gedit、sumlime、notepad等,推荐使用vi和vim编程;

4) SHELL编程内容第一行以#!开头,其后接SHELL解释器的类型,例如/bin/bash等,正文每个功能写一行,逐行编写;

5) SHELL脚本在被执行时,从上往下执行,SHELL指令从上到下;

Shell中的四则运算

运算符 含义
+ 加法运算
- 减法运算
* 乘法运算
/ 除法运算

其它运算符 =、==、!=、!、-o、-a

运算符 含义
% 求余
== 相等
= 赋值
!= 不相等
!
-o
-a

 

关系运算符

运算符 含义
-eq 两个数相等返回true
-ne 两个数不相等返回true
-gt 左侧数大于右侧数返回true
-It 左侧数小于右侧数返回true
-ge 左侧数大于等于右侧数返回true
-le 左侧数小于等于右侧数返回true

测试两个数值是否相等;

[root@localhost ~]# [ 1024 -eq 1024 ]           //测试1024是否等于1024
[root@localhost ~]# echo $?
0                                               //两个数值相等
修改第一个数值为1124后再次进行测试。
[root@localhost ~]# [ 1124 -eq 1024 ]
[root@localhost ~]# echo $?
1                                               //两个数值不相等
[root@localhost ~]# number1=500                 //number1为500
[root@localhost ~]# number2=254                 //number2为254
[root@localhost ~]# [ $number1 -gt $number2 ]
[root@localhost ~]# echo $?
0                                               //number1大于number2
[root@localhost ~]#

 

字符串运算符

 

运算符 含义
= 两个字符串相等返回true
!= 两个字符串不相等返回true
-z 字符串长度为0返回true
-n

字符串长度不为0返回true

运算符

含义
-d file 检测文件是否是目录,如果是,则返回 true
-r file 检测文件是否可读,如果是,则返回 true
-w file 检测文件是否可写,如果是,则返回 true
-x file 检测文件是否可执行,如果是,则返回 true
-s file 检测文件是否为空(文件大小是否大于0,不为空返回 true
-e file 检测文件(包括目录)是否存在,如果是,则返回 true
要测试两个字符串是否相等
[root@localhost ~]# [ "abc" = "abc" ]
[root@localhost ~]# echo $?
0                                        //两个字符串相等
把第一个字符串更改为bac后进行测试
[root@localhost ~]# [ "bac" = "abc" ]
[root@localhost ~]# echo $?
1                                        //两个字符串不相等
如果把运算符改为“!=”
[root@localhost ~]# [ "bac" != "abc" ]
[root@localhost ~]# echo $?
0
判断环境变量是否为空或者非空
[root@localhost ~]# [ -z $python1 ]
[root@localhost ~]# echo $?
0
[root@localhost ~]# [ -n $python1 ]
[root@localhost ~]# echo $?
0                                        //python1变量为空
[root@localhost ~]# python1="test"       //对python1变量进行赋值
[root@localhost ~]# [ -z $python1 ]
[root@localhost ~]# echo $?
1                                        //python1变量不为空
[root@localhost ~]#

 

条件测试的逻辑操作符

逻辑操作符分以下3种:

  • -a:逻辑与,只有当操作符两边的条件均为真时,结果为真,否则为假。

  • -o:逻辑或,操作符两边的条件只要有一个为真,结果为真,只有当两边所有条件为假时,结果为假。

  • !:逻辑否,条件为假,结果为真。

 

如果要测试两个文件的状态
[root@localhost 20190105]# ll test1 test2
-rw-rw-r--. 1 root root 0 6月   4 09:25 test1
-rw-rw-r--. 1 root root 0 6月   4 09:25 test2
[root@localhost 20190105]# [ -r test1 -a -r test2 ] //测试文件 test1 和 test2 是否都可读
[root@localhost 20190105]# echo $?
0
[root@localhost 20190105]# [ -x test1 -o -x test2 ] //测试文件 test1 和 test2 是否至少有一个可执行
[root@localhost 20190105]# echo $?
1
如果要测试两个数值变量
[root@localhost 20190105]# number1=10
[root@localhost 20190105]# number2=20
[root@localhost 20190105]# [ $number1 -eq 10 -a $number2 -gt 20 ] //测试是否number1 大于10 且 number2 大于20
[root@localhost 20190105]# echo $?
1
如果要测试文件test1 是否为不可读
[root@localhost 20190105]# ls -l test1
-rw-rw-r--. 1 root root 0 6月   4 09:25 test1
[root@localhost 20190105]# [ ! -r test1 ] //测试文件test1 是否为不可读
[root@localhost 20190105]# echo $?
1
[root@localhost 20190105]#

 

条件测试的逻辑操作符

逻辑操作符分以下3种:

  • -a:逻辑与,只有当操作符两边的条件均为真时,结果为真,否则为假。

  • -o:逻辑或,操作符两边的条件只要有一个为真,结果为真,只有当两边所有条件为假时,结果为假。

  • !:逻辑否,条件为假,结果为真。

 

如果要测试两个文件的状态
[root@localhost 20190105]# ll test1 test2
-rw-rw-r--. 1 root root 0 6月   4 09:25 test1
-rw-rw-r--. 1 root root 0 6月   4 09:25 test2
[root@localhost 20190105]# [ -r test1 -a -r test2 ] //测试文件 test1 和 test2 是否都可读
[root@localhost 20190105]# echo $?
0
[root@localhost 20190105]# [ -x test1 -o -x test2 ] //测试文件 test1 和 test2 是否至少有一个可执行
[root@localhost 20190105]# echo $?
1
如果要测试两个数值变量
[root@localhost 20190105]# number1=10
[root@localhost 20190105]# number2=20
[root@localhost 20190105]# [ $number1 -eq 10 -a $number2 -gt 20 ] //测试是否number1 大于10 且 number2 大于20
[root@localhost 20190105]# echo $?
1
如果要测试文件test1 是否为不可读
[root@localhost 20190105]# ls -l test1
-rw-rw-r--. 1 root root 0 6月   4 09:25 test1
[root@localhost 20190105]# [ ! -r test1 ] //测试文件test1 是否为不可读
[root@localhost 20190105]# echo $?
1
[root@localhost 20190105]#

 

test命令

 

test $[num1] -eq $[num2]  #判断两个变量是否相等
test num1=num2  #判断两个数字是否相等

 

参数 含义
-e file 文件存在则返回真
-r file 文件存在并且可读则返回真
-w file 文件存在并且可写则返回真
-x file 文件存在并且可执行则返回真
-s file 文件存在并且内容不为空则返回真
-d file 文件目录存在则返回真

 

Bash脚本的用法展示

一、条件选择、判断(if·、case)

二、四个循环(for、while、until、select)

三、循环里的一些命令与技巧(continue、break、shift...)

四、信号捕获trap

 

条件判断 :

    如果用户不存在

                添加用户,给密码并显示添加成功;

     否则

               显示如果以及没在,没有添加;

bash中如何实现条件判断?

条件测试类型 :

        整数测试

        字符测试

        文件测试

条件测试的表达式 :

     [ expression ]

     [ [ expression ] ]

     test expression

 

整数比较 :

     -eq : 测试两个整数是否相等,比如$A -eq $B

    -ne : 测试两个整数是否不等:不等,为真;相等,为假;

    -gt : 测试一个数是否大于另一个数:小于,为真;否则,为假;

    -lt : 测试 一个数是否小于另一个数:小于,为真;否则,为假;

    -gt : 大于或等于

    -gt : 小于或等于

 

命令的间逻辑关系 :

    逻辑与 :&&

           第一个条件为假时,第二条件不用再判断,最终结果已经有;

          第一个条件为真时,第二条件必须得判断;

    逻辑或 :||

 

如果用户user6 不存在,就添加用户user6

! id user6 && useradd user6

id user6 || useradd user6

 

如果/etc/inittab文件的行数大于100,就显示好大的文件。

[ 'wc -l /etc/inittab | cut -d' '-f1' -gt 100 ] && echo "Large file."

 

变量名称 :

    1、只能包含字母、数字和下划线,并且不能数字开头;

     2、不应该跟系统中已有的环境变量重名;

     3、最好做到见名知义

 

如果用户存在,就显示用户已存在:否则,就添加此用户;

id user1 && echo "user1 exists." || useradd user1

如果用户不存在,就添加:否则,显示其已经存在;

! id user1 && useradd user1 || echo "user1 exists."

如果用户不存在,添加并且给密码:否则,显示其已经存在

! id user1 && useradd user1 && echo "user1" | passwd --stdin user1 || echo "user1 exists."

 

shell中如何进行算术运算 :

A=3

B=6

1、let 算术运算表达式

        let c=$A+$B

2、$[算术运算表达式]

       C=$[$A+$B]

3、$([算术运算表达式])

      C=$(($A+$B))

4、expr算术运算表达式,表达式中各操作及运算符要有空格 , 而且要使用命令引用。

      C='expr $A + $B'

 

案例 :

给定一个用户,判断其UID与GID是否一样,如果一样,就显示此用户为“good guy”: 否则,就显示此用户为“bad guy”

#!/bin/bash

USERNAME=user1

USERID='id -u $USERNAME'

GROUPID='id -g $USERNAME'

if [ $USEID -eq $GROUPID ];then

   echo "Good guy"

else

  echo "Bad guy"

fi

进一步要求:不使用id命令获得其id号:

#!/bin/bash

#

USERNAME=user1

USERID='grep "^USERNAME\>" /etc/passwd |cut -d :-f3'

GROUPID='grep "^USERNAME\>" /etc/passwd |cut -d :-f3'

if [ $USERID -    eq $ GROUPID ]; then

     echo "Goo guy."

else

    echo "Bad guy."

fi

 

 

二、Shell编程四剑客(findsedawkgrep)功能及用途:

Find工具:主要用于文件、文件夹的查找,找到文件的路径;

Sed工具:非交互模式编辑器、vim交互式编辑器,用于文件内容修改;

Awk工具:主要用于对文件内容进行处理、输出预定的结果;

Grep工具:主要用于操作系统文件内容的查找,对文件的内容的操作,匹配文件中的关键词;

 

Find命令工具:

主要用于对操作系统文件路径的查找;

find   path   -option   [   -print ]   [ -exec   -ok   command ]   { }  \;

  1. find . 查找当前目录所有文件、文件夹;
  2. find / -name "test.txt"|xargs rm -rf {} \;查找test.txt文件并删除;
  3. find . -name "*.txt" -exec cp  {}  /root/ \;查找当前目录以.txt结尾文件,并且将该文件cp至/root目录;(推荐使用exec)
  4. 恢复/tmp/下文件、目录原来权限;
  5. 文件权限默认是:644

    目录权限默认是:755

    find . -type d  -exec  chmod 755 -R {}  \;\;结束标记)修改当前目录,类型是目录的权限改完默认权限;

    find . -type f -exec chmod 644 -R {} \; 修改当前目录,类型是文件的权限改完默认权限;

  6. 查找当前目录文件大小,-size参数:find .  -size +20M -a -size -200M -exec rm -rf {} \;
  7. find . -name "*.log" ! -name "access.log" ! -name "error.log" -size +30M -size -40M  -type f
  8. 按天数、时间去查找文件及文件夹;

       find . -name "*.log" ! -name "access.log" ! -name "error.log" -mtime +30 -exec rm -rf {} \;-mtime    -n +n                            #按文件更改时间来查找文件,-n指n天以内,+n指n天以前;

 

          -atime    -n +n                             #按文件访问时间来查找文件;

         -ctime    -n +n                             #按文件创建时间来查找文件;

      9.查找系统所有的以.rpm结尾的软件包,并且将软件包拷贝至/root/20180327/;

find / -name "*.rpm" -exec cp {} /root/20180327/ \;

     10.find / -name httpd 查找系统httpd名称的文件或者目录;

          find  /  -name access.log 查找系统access.log路径;

          find  /usr/ -name  “*.log”查看以.log结尾的文件,*表示0个或者多个匹配;

        查找当前目录名称以.log结尾,是文件属性,大小大于100M,权限是644的文件:

          find . -name "*.log" -type f -size +100M -perm 644 ! -name "test1.log"

atime:access time,文件被访问的时间;

ctime:change time,文件属性被修改时间;

mtime:modify time,文件内容修改时间

查找txt文档,修改时间,小于一天,大于5M,权限755

2e75bc90c7cc56108f2567f357fdae742f9.jpg

查找log文件,大于100M,权限644,去掉test1.log文件,修改时间小于30分钟

find . -name "*.log" -type f -size +100M -perm 644 ! -name "test1.log" -mtime -30 -mmin -1

拷贝到/tmp目录、在当前目录,只有一级目录

6225b5324f4131fc9bc0a16108fb4f0287b.jpg

9f3f80402367396b3e9d2f38dc3069fd896.jpg

 

Shell脚本介绍(资源)_第4张图片

应用场景:

根据你的需求,假设网卡的配置文件:

eth0查找网卡的配置文件,修改IP;

Shell脚本介绍(资源)_第5张图片

恢复权限

恢复文档文件权限

find . -type f -exec chmod -R 644 {} \;

恢复目录权限

find . -type d -exec chmod -R 755 {} \;

把大于5M的文件文档,移到/tmp/目录

f952d188775283c43a736ca53e328e9cdb3.jpg

 

Sed命令工具:

SED是一个非交互式文本编辑器,它可对文本文件和标准输入进行编辑,标准输入可以来自键盘输入、文本重定向、字符串、变量,甚至来自于管道的文本,与VIM编辑器类似,它一次处理一行内容,Sed可以编辑一个或多个文件,简化对文件的反复操作、编写转换程序等。

在处理文本时把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),紧接着用SED命令处理缓冲区中的内容,处理完成后把缓冲区的内容输出至屏幕或者写入文件。

逐行处理直到文件末尾,然而如果打印在屏幕上,实质文件内容并没有改变,除非你使用重定向存储输出或者写入文件。其语法参数格式为:

sed '/^SELINUX/s/enforcing/disabled/g' /etc/selinux/config          #把enforcing/disabled/替换成/etc/selinux/config   

sed 's/^SELINUX.*/SELINUX=disabled /g' /etc/selinux/config        #把所有的SELINUX=disabled替换成/etc/selinux/config 

 

基于sed打印最大、最小值:

238739

23923823

322938293829832

328922222222228

2382938923

-293238293

使用#sed 's/ /\n/g' test.txt|grep -v "^$"|sort -n|sed -n "1p;$"p查询

-8923293892839283928

3242348923233232323

 

591f706a9ffed5ceae1c87ce65b08814c7c.jpg

匹配IP地址

145c9bac52a2e7be05041f12498908c9b9d.jpg

严格匹配IP地址

7c74fa2f8c25c2bb0c42e7ab7be2a56c9a9.jpg

意思同上

843e61680215cd4f98a225815728a69c442.jpg

 

shell变量为弱类型,定义变量不需要声明类型,但使用时需要明确变量大的类型,可以是使用Declare指定类型,Declare常见参数:

+/-    "-"可用来指定变量的属性,“+”为取消变量所设的属性

-f     仅显示函数

r       将变量设置为只读

x     指定的变量会成为环境变量,可供shell以外的程序来使用。

i      指定类型为数值,字符串或运算符

SHELL变量详解

  1. 变量是一个可变的值,SHELL变量主要是为了减少重复引用;
  2. SHELL变量是弱类型,使用时直接=赋值即可,ABC=123,ABC是变量名称,123位变量的值;
  3. SHELL变量在定义的时候不需要声明,可以声明,declare声明;

shell使用案例:

#!/bin/bash

wget  https://mirrors.tuna.tsinghua.edu.cn/apache/httpd/httpd-2.4.27.tar.bz2

yum update apr apr-devel apr-util apr-util-devel -y

tar -xf httpd-2.4.27.tar.bz2

cd httpd-2.4.27

./configure --prefix=/usr/local/apache2/ --enable-so  --enable-rewrite  --enable-ssl

make 

make install

2)、自动删除test.txt文件脚本,脚本的功能实现从/root/目录cp拷贝test.txt到/tmp目录,并且在/tmp目录创建一个目录abc,并且删除原/root下test.txt。

#!/bin/bash

#the auto cp file and rm files

FILES=/root/test.txt               #把/root/test.txt定义为FILES

DIR=/tmp              #把/tmp定义为DIR   

cp $FILES $DIR

mkdir -p $DIR/abc

rm -rf $FILES

echo "--------------"

echo "The shell exec scuccessful"

 

2)Shell编程特点:

q  语法和结构通常比较简单;

q  学习和使用通常比较简单;

q  基于Shell解释器运行,不需要编译运行;

q  程序的开发产能优于运行效能。

3)Linux Shell的种类非常多,常见的SHELL分类

q  Bourne Shell(/usr/bin/sh或/bin/sh)

Bourne Again Shell/bin/bash)最常用,大部分系统自带!

q  C Shell(/usr/bin/csh)

q  K Shell(/usr/bin/ksh)

q  Shell for Root(/sbin/sh)

注:shell是操作系统的最外层,shell可以合并编程语言以控制进程和文件,以及启动和控制其他程序。

简单来说:shell就是一个用户跟操作系统之间交互的命令解释器

如图,shell在系统各种的位置

Shell脚本介绍(资源)_第6张图片

shell独立于内核,它是链接内核和应用程序的桥梁。内核是linux系统的心脏,从开机自检就驻扎在计算机内存中,直到计算机关闭为止。用户的应用程序存储在计算机硬盘上,仅当需要时才被调入内存。shell是一种应用程序,当用户登陆linux系统时,shell就会被调用到内存执行。

查看常见的shell解释器

[root@localhosts ~]# cat /etc/shells 
/bin/sh
/bin/bash
/sbin/nologin
/bin/tcsh
/bin/csh

注意:/bin/bash是大多数linux中默认的shell解释器之后的所有脚本的编写都是bash脚本

我们来编写第一个脚本frist.sh

linux不以后缀名区分文件,为了方便记忆这里我就以.sh为结尾

写第一个脚本:

[root@localhosts 桌面]# vim first.sh
#!/bin/bash
#auto my frist scripts
#by  authors cd
echo "hello world"
mkdir /root/shell
free -m

注释:

#!/bin/bash 主要是为了声明,我所写的均为bash语言(我是用的是bash解释器)[定义我的脚本是shell脚本].{固定格式}

第二行为注释行,注释信息不生效

#auto echo  hello world!

#by authors tree 2016   本脚本是由谁来写的,写这个是为了完成什么目的。

执行过程

[root@localhosts ~]# ll first.sh         #查看是否具有执行权限
-rw-r--r-- 1 root root 65 Aug 30 06:50 first.sh
[root@localhosts ~]# chmod   o+x first.sh           #添加执行权限
[root@localhosts ~]# ll first.sh          #查看是否具有执行权限
-rwxr-xr-x 1 root root 65 Aug 30 06:50 first.sh

执行的结果

[root@localhosts ~]# ./first.sh 
hello world
           total       used       free     shared    buffers     cached
           Mem:          2006        728       1277          0         28        330
-/+ buffers/cache:        370       1636
Swap:         1999          0       1999

或者可以用 /bin/bash/+脚本来执行,这样的就不需要加权限了。

 

编写LAMP YUM自动安装脚本

[root@localhosts ~]# vim lamp.sh 
#!/bin/bash
#2018/5/23
#auto install linux for lamp
#Intall HTTP WEB service
yum install httpd httpd-devel -y
#Intall MYSQL service
yum install mysql-server mysql mysql-devel –y
#Intall PHP service
yum install php php-devel php-mysql –y
#启动httpd和mysql服务,并关闭防火墙和selinux
/etc/init.d/httpd restart
/etc/init.d/mysqld restart
/etc/init.d/iptables stop 
setenforce 0
echo "The shell script Exec Success."
exit

执行脚本,就能自动安装LAMP了。

[root@localhosts ~]# sh lamp.sh 

Shell脚本介绍(资源)_第7张图片

Shell脚本介绍(资源)_第8张图片

使用命令:>>/var/www/html/phpinfo.php       追加到/var/www/html/phpinfo.php 中。

Shell脚本介绍(资源)_第9张图片

 

执行脚本的不同方式

第一种使用绝对路径执行                 例如 :  /bin/bash first_shell.sh

第二种使用相对路径执行,如./的方式                       ./first_shell.sh

第三种使用 sh命令来执行  格式  sh 脚本名   不需要执行权限             sh first_shell.sh

第四种使用 . (空格)脚本名称的方式执行  不需要执行权限  . a.sh

第五种使用 source 脚本名称        不需要执行权限(主要用于生效配置文件)

注意:建议使用后三种,在生产环境中不要轻易的给文件可执行权限;

执行脚本的方法

$source ./script.sh

或者

$ . ./script.sh

source或者.命令是shell的内建命令,这种方式也不会创建子shell,而是直接在交互式

shell下逐行执行脚本中的命令。

 

2、变量

变量用来保存有用信息,比如路径名,文件名,数字等,变量的本质是存储数据的一个或多个计算机内存地址

接下来我们来探讨脚本中作重要的东西---变量,变量的定义是:可以存放一个可变的值的空间

可以通过不同的环境进行改变就是一个可以变的值.

 

默认情况下: 在Linux中可以将每个shell看成不同的执行环境,所以相同的一个变量名称在不同的变量执行环境中的变量值是不同的.

常见的shell变量分类

自定义变量、环境变量、位置变量、预定义变量

变量的输出

一般使用echo 输出变量   echo $变量名

shell变量总结:

1.     声明变量不用声明类型

2.     可以存储不同类型内容

3.     使用时要明确变量类型

区分大小写。

自定义变量

自定义变量是用户根据自己的环境自己定义的变量,Bash中比较简单的变量;

不用进行提前声明,而是直接指定变量名称并赋给初始值;

定义变量的基本格式为 变量名=变量值

要求:

等号两遍不允许出现空格;

变量名称只能以字母和下划线开头名称中不能包含+、- * 、 / . , 、 ? % *  等一些特殊字符.

举例: var=”hello world”

 

 

变量名的命名须遵循如下规则:

首个字符必须为字母(a-z,A-Z)。

中间不能有空格,可以使用下划线(_)。

不能使用标点符号。

不能使用bash里的关键字(可用help命令查看保留关键字)。

 

 

变量的使用:

格式:$变量名或者${变量名}

echo $var 或者echo ${var}

举例: 来进行定义一个变量名字为Linux值为7.2 

[root@localhosts ~]# Linux=7.2      #为变量Linux赋值
[root@localhosts ~]# echo $Linux    #输出变量Linux的值
7.2
[ro[root@localhosts ~]# linux=6.5      #为变量linux赋值
[ro[root@localhosts ~]# echo $linux      #输出变量linux的值
6.5

可以直接在命令行定义一个变量并赋予值,通过echo进行输出变量 $是引用变量的特殊字符(必须使用$符号)

echo和调用的变量之间必须要有空格

注意大小写的变量的值是不同的

举例2:当需要一起调用两组变量时

[root@localhosts ~]#echo $Linux $linux
7.2 6.5

直接使用echo 后面跟$调用的变量 如果有多个则空格隔开

举例3:当变量名和后面的字符容易混淆的时候应该使用{}将变量名括起来

[root@localhosts ~]#echo system{$Linux}
system{7.2}

取消变量:

语法:unset +变量

[root@localhosts ~]# unset linux
[root@localhosts ~]# echo $linux

其他的特殊操作

 

双引号( " )

1.当=号右边赋值出现空格的时候,需要使用双引号将其扩起

[root@localhosts ~]# webserver=" nginx 1.11"
[root@localhosts ~]# echo $webserver 
nginx 1.11

2、来看下没有引号,有单引号和双引号的区别

# Y=a
# echo $Y
a

# echo '$x' 
$x 
# echo "$x" 

 

read命令

除了上面的赋值之外还可以使用read命令进行赋值,read命令用来提示用户输入信息,从而实现简单的交互式过程(其实我们所输入的命令就是一种交互式的过程)

执行时需要从标准输入设备键盘读取一行,并以空格为分隔符

执行时需要从标准输入设备键盘读取一行,并以空格为分隔符

[root@xuegod63 ~]# read kernel system      #同时定义两个变量操作      

3.10 7.2     -à手动输入的变量值

 

由于read命令提供了-p参数,这里可以缩写为:

#!/bin/bash

#by authors tree 20160904

read  -p "Enter your name: "  name

 

echo "hello $name,welcome to my class"

exit 0

注意:

由于使用read存在一定的风险,既有可能需要等待用户输入,但用户一直不输入,就没法继续运行。

这时候可以使用read的另外一个参数-t

-t是一个计时器,指定read命令需要等待输入的秒数,当计时满时,直接返回一个非零退出状态。

 

#!/bin/bash 

if read -t 5 -p "please enter your name:" name 

then 

    echo "hello $name ,welcome to my script" 

else 

    echo "sorry,too slow" 

fi 

exit 0 

  1. SHELL编程实战优化
  1. SHELL脚本优化引入变量;

SHELL变量,是一个可变的值,跟常量是对应关系,常量是一个固定的值,变量可变;

变量相当于别名,xiaoming=110101199410234012,获取身份证ID号,$xiaoming;

  1. SHELL脚本引入if、for、while、case条件判断;
  2. 检查SHELL脚本功能、需求是否有缺陷;
  3. 检查SHELL脚本能否扩展,批量生产!

 

SHELL9个实例  : 

 

1、 获取随机字符串或数字

获取随机8位字符串:

Shell脚本介绍(资源)_第10张图片

获取随机8位数字:

Shell脚本介绍(资源)_第11张图片

2 、定义一个颜色输出字符串函数

Shell脚本介绍(资源)_第12张图片

3、 批量创建用户

Shell脚本介绍(资源)_第13张图片

4 、检查软件包是否安装

Shell脚本介绍(资源)_第14张图片

5、 检查服务状态

Shell脚本介绍(资源)_第15张图片

6 、检查主机存活状态

方法1: 将错误IP放到数组里面判断是否ping失败三次

Shell脚本介绍(资源)_第16张图片

方法2: 将错误次数放到FAIL_COUNT变量里面判断是否ping失败三次

Shell脚本介绍(资源)_第17张图片

方法3: 利用for循环将ping通就跳出循环继续,如果不跳出就会走到打印ping失败

Shell脚本介绍(资源)_第18张图片

7 、监控CPU、内存和硬盘利用率

1)CPU

借助vmstat工具来分析CPU统计信息。

Shell脚本介绍(资源)_第19张图片

2)内存    

Shell脚本介绍(资源)_第20张图片

3)硬盘

Shell脚本介绍(资源)_第21张图片

8 、批量主机磁盘利用率监控

前提监控端和被监控端SSH免交互登录或者密钥登录。

写一个配置文件保存被监控主机SSH连接信息,文件内容格式:IP User Port

Shell脚本介绍(资源)_第22张图片

9 、检查网站可用性

1)检查URL可用性

Shell脚本介绍(资源)_第23张图片

2)判断三次URL可用性

思路与上面检查主机存活状态一样。

Shell脚本介绍(资源)_第24张图片

10、用ping命令统计某个网段的IP状态,如192.168.0,200到254之间的IP登录状态情况。

答 : #!/bin/bash

#

NET=192.168.0

trap 'echo "quit ."';exit 1INT       #添加捕捉信号,按CTRL+C,退出

for I in {200..254}; do

 if ping -c 1 -W 1 $NET.$I &> /dev/null; then

    echo "$NET.$I is up."

 else

    echo "$NET.$I is down."

 fi

done

 

11、查看用户有没有登录,并每个一段时间刷新。

#!/bin/bash
#
who |grep "hadoop" &> /dev/null
RETVAL=$?

until [ $RETVAL -eq 0  ]; do
 echo "hadoop is no come."
 sleep 5
 who | grep "hadoop" &> /dev/null
 RETVAL=$?
done

echo "hadoop is logged in."

 

12、100以内正整数的和

#!/bin/bash

declare -i SUM=0

for I  in (1..100); do

 let SUM+=$I

done

 

echo $SUM

declare -i SUM2=0

for ((J=2,I<100,J+=2)); do

 let SUM2+=$J

done

 

echo $SUM2

 

13、写一个猜数字脚本,当用户输入的数字和预设数字(随机生成一个小于100的数字)一样时,直接退出,否则让用户一直输入,并且提示用户的数字比预设数字大或者小。

答 : #!/bin/bash
m=`echo $RANDOM`
n1=$[$m%100]
while :
do
    read -p "Please input a number: " n
    if [ $n == $n1 ]
    then
        break
    elif [ $n -gt $n1 ]
    then
        echo "bigger"
        continue
    else
        echo "smaller"
        continue
    fi
done
echo "You are right."

 

14、1、写一个脚本执行后,输入名字,产生随机数01-99之间的数字。
2、如果相同的名字重复输入,抓到的数字还是第一次抓取的结果,
3、前面已经抓到的数字,下次不能在出现相同数字。
4、第一个输入名字后,屏幕输出信息,并将名字和数字记录到文件里,程序不能退出
继续等待别的学生输入。

while :

do

read -p  "Please input a name:" name

  if [ -f /work/test/1.log ];then

     bb=`cat /work/test/1.log | awk -F: '{print $1}' | grep "$name"`

     if [ "$bb" != "$name" ];then  #名字不重复情况下

        aa=`echo $RANDOM | awk -F "" '{print $2 $3}'`

         while :

          do

       dd=`cat  /work/test/1.log |  awk -F: '{print $2}'  | grep "$aa"`

          if [ "$aa"  ==  "$dd" ];then   #数字已经存在情况下

            echo "数字已存在."

            aa=`echo $RANDOM | awk -F "" '{print $2 $3}'`

           else

            break

          fi

          done

        echo "$name:$aa" | tee -a /work/test/1.log

     else

     aa=`cat /work/test/1.log |  grep "$name" | awk -F: '{print $2}'` #名字重复

       echo $aa

       echo "重复名字."

     fi

  else

      aa=`echo $RANDOM | awk -F "" '{print $2 $3}'`

      echo "$name:$aa" | tee -a  /work/test/1.log

  fi

done

 

15、写一个猜数字脚本,当用户输入的数字和预设数字(随机生成一个小于100的数字)一样时,直接退出,否则让用户一直输入,并且提示用户的数字比预设数字大或者小。

#!/bin/bash
m=`echo $RANDOM`
n1=$[$m%100]
while :
do
    read -p "Please input a number: " n
    if [ $n == $n1 ]
    then
        break
    elif [ $n -gt $n1 ]
    then
        echo "bigger"
        continue
    else
        echo "smaller"
        continue
    fi
done
echo "You are right."

 

16、创建一个函数,能接受两个参数:
1)第一个参数为URL,即可下载的文件;第二个参数为目录,即下载后保存的位置;
2)如果用户给的目录不存在,则提示用户是否创建;如果创建就继续执行,否则,函数返回一个51的错误值给调用脚本;
3)如果给的目录存在,则下载文件;下载命令执行结束后测试文件下载成功与否;如果成功,则>返回0给调用脚本,否则,返回52给调用脚本;

提示,在函数中返回错误值给调用脚本,使用return

答  :

#!/bin/bash

 

if [ ! -d $2 ]

then

    echo "please make directory"

    exit 51

fi

cd $2

wget $1

n=`echo $?`

if [ $n -eq 0 ];then

    exit 0

else

    exit 52

fi

 

17、脚本的功能:
脚本可以带参数也可以不带,参数可以有多个,每个参数必须是一个目录,脚本检查参数个数,若等于0,则列出当前目录本身;否则,显示每个参数包含的子目录。

#!/bin/bash
if [ $# == 0 ]
then
ls -ld `pwd`
else
for i in `seq 1 $#`
do
a=$i
echo "ls ${!a}"
ls -l ${!a} |grep '^d'
done
fi
 

标注: 你可能会对${!a}有疑问,这里是一个特殊用法,在shell中,$1为第一个参数,$2为第二个参数,以此类推,那么这里的数字要是一个变量如何表示呢?比如n=3,我想取第三个参数,能否写成 $$n? shell中是不支持的,那怎么办? 就用脚本中的这种方法:  a=$n, echo ${!a} 

 

18、提示用户输入网卡的名字,然后我们用脚本输出网卡的ip。 看似简单,但是需要考虑多个方面,比如我们输入的不符合网卡名字的规范,怎么应对。名字符合规范,但是根本就没有这个网卡有怎么应对。

#!/bin/bash

while :

do

     read -p "请输入网卡名: " e

     e1=`echo "$e" | sed 's/[-0-9]//g'`

     e2=`echo "$e" | sed 's/[a-zA-Z]//g'`

     if [ -z $e ]

     then

        echo "你没有输入任何东西"

        continue

     elif [ -z $e1 ]

     then

        echo "不要输入纯数字在centos中网卡名是以eth开头后面加数字"

        continue

     elif [ -z $e2 ]

     then

        echo "不要输入纯字母在centos中网卡名是以eth开头后面加数字"

        continue

     else

        break

     fi

done

ip() {

        ifconfig | grep -A1 "$1 " |tail -1 | awk '{print $2}' | awk -F ":" '{print $2}'

}

myip=`ip $e`

if [ -z $myip ]

then

    echo "抱歉,没有这个网卡。"

else

    echo "你的网卡IP地址是$myip"

fi

 

19、写一个脚本,执行后,打印一行提示“Please input a number:",要求用户输入数值,然后打印出该数值,然后再次要求用户输入数值。直到用户输入"end"停止。

 

#!/bin/bash

while :

do

        read -p "Please input a number:(end for exit) " n

        num=` echo $n |sed -r 's/[0-9]//g'|wc -c `

        if [ $n == "end" ]

                then

                        exit

                elif [ $num -ne 1  ]

                        then

                        echo "what you input is not a number!Try again!"

                else

                        echo "your input number is: $n"

        fi

done

 

20、使用传参的方法写个脚本,实现加减乘除的功能。例如:  sh  a.sh  1   2,这样会分别计算加、减、乘、除的结果。

 

要求:

1 脚本需判断提供的两个数字必须为整数

2 当做减法或者除法时,需要判断哪个数字大

3 减法时需要用大的数字减小的数字

4 除法时需要用大的数字除以小的数字,并且结果需要保留两个小数点。

#!/bin/bash

if [ $# -ne 2 ]

then

    echo "The number of parameter is not 2, Please useage: ./$0 1 2"

    exit 1

fi

 

is_int()

{

    if echo "$1"|grep -q '[^0-9]'

    then

    echo "$1 is not integer number."

    exit 1

    fi

}

 

max()

{

    if [ $1 -ge $2 ]

    then

    echo $1

    else

    echo $2

    fi

}

 

min()

{

    if [ $1 -lt $2 ]

    then

    echo $1

    else

    echo $2

    fi

}

 

sum()

{

    echo "$1 + $2 = $[$1+$2]"

}

 

minus()

{

    big=`max $1 $2`

    small=`min $1 $2`

    echo "$big - $small = $[$big-$small]"

}

 

mult()

{

    echo "$1 * $2 = $[$1*$2]"

}

 

div()

{

    big=`max $1 $2`

    small=`min $1 $2`

    d=`echo "scale =2; $big / $small"|bc`

    echo "$big / $small = $d"

}

 

is_int $1

is_int $2

sum $1 $2

minus $1 $2

mult $1 $2

div $1 $2

 

21、写一个脚本: 计算100以内所有能被3整除的正整数的和

#!/bin/bash
sum=0
for i in {1..100};do
    if [ $[$i%3] -eq 0 ];then
    sum=$[$i+$sum]
     fi
done

echo "sum:$sum"

 

22、

#!/bin/bash

#written by aming.

if [ $# -eq 0 -o $# -gt 2 ]

then

    echo "use $0 --add username or $0 --del username or $0 --help."

    exit 1

fi

case $1 in

    --add)

        n=0

        for u in `echo $2|sed 's/,/ /g'`; do

            if awk -F: '{print $1}' /etc/passwd |grep -qw "$u"

            then

                echo "The user $u exist."

            else

                useradd $u

                echo -e "$u\n$u"|passwd $u >/dev/null 2>&1

                echo "The user $u added successfully."

                n=$[$n+1]

            fi

        done

        if [ $n -eq 0 ]; then

            exit 2

        fi

        ;;

    --del)

        n=0

        for u in `echo $2|sed 's/,/ /g'`; do

            if awk -F: '{print $1}' /etc/passwd|grep -qw "$u"

            then

                userdel -r $u

                echo "The user $u deleted successfully."

                n=$[$n+1]

            else

                echo "The user $u not exist."

            fi

        done

        if [ $n -eq 0 ]; then

                exit 3

        fi

        ;;

    --help)

        echo -e "--add can add user,and the passwd is the same as username.     

    It can add multiuser such as --add user1,user2,user3..."

        echo "--del cat delete user.It can delete user such as --del user1,user2,user3..."

        ;;

    *)

        echo "use $0 --add username or $0 --del username or $0 --help."

        exit 1

        ;;

esac

 

23、要求如下:

 

  • 只支持三个选项 ‘--del’ ‘--add’ --help输入其他选项报错。

  • 使用‘--add’需要验证用户名是否存在,存在则反馈存在。且不添加。 不存在则创建该用户,切添加与该用户名相同的密码。并且反馈。

  • 使用‘--del’ 需要验证用户名是否存在,存在则删除用户及其家目录。不存在则反馈该用户不存在。

  • --help 选项反馈出使用方法

  • 支持以,分隔   一次删除多个或者添加多个用户。

  • 能用echo $?  检测脚本执行情况  成功删除或者添加为0,报错信息为其他数字。

  • 能以,分割。一次性添加或者 删除多个用户。  例如 adddel.sh --add user1,user2,user3.......

  • 不允许存在明显bug。

#!/bin/bash

#written by aming.

if [ $# -eq 0 -o $# -gt 2 ]

then

    echo "use $0 --add username or $0 --del username or $0 --help."

    exit 1

fi

case $1 in

    --add)

        n=0

        for u in `echo $2|sed 's/,/ /g'`; do

            if awk -F: '{print $1}' /etc/passwd |grep -qw "$u"

            then

                echo "The user $u exist."

            else

                useradd $u

                echo -e "$u\n$u"|passwd $u >/dev/null 2>&1

                echo "The user $u added successfully."

                n=$[$n+1]

            fi

        done

        if [ $n -eq 0 ]; then

            exit 2

        fi

        ;;

    --del)

        n=0

        for u in `echo $2|sed 's/,/ /g'`; do

            if awk -F: '{print $1}' /etc/passwd|grep -qw "$u"

            then

                userdel -r $u

                echo "The user $u deleted successfully."

                n=$[$n+1]

            else

                echo "The user $u not exist."

            fi

        done

        if [ $n -eq 0 ]; then

                exit 3

        fi

        ;;

    --help)

        echo -e "--add can add user,and the passwd is the same as username.     

    It can add multiuser such as --add user1,user2,user3..."

        echo "--del cat delete user.It can delete user such as --del user1,user2,user3..."

        ;;

    *)

        echo "use $0 --add username or $0 --del username or $0 --help."

        exit 1

        ;;

esac

 

24、假设,当前MySQL服务的root密码为123456,写脚本检测MySQL服务是否正常(比如,可以正常进入mysql执行show processlist),并检测一下当前的MySQL服务是主还是从,如果是从,请判断它的主从服务是否异常。如果是主,则不需要做什么

#!/bin/bash

Mysql_c="mysql -uroot -p123456"

$Mysql_c -e "show processlist" >/tmp/mysql_pro.log 2>/tmp/mysql_log.err

n=`wc -l /tmp/mysql_log.err|awk '{print $1}'`

if [ $n -gt 0 ]

then

    echo "mysql service sth wrong."

else

    $Mysql_c -e "show slave status\G" >/tmp/mysql_s.log

    n1=`wc -l /tmp/mysql_s.log|awk '{print $1}'`

    if [ $n1 -gt 0 ]

    then

        y1=`grep 'Slave_IO_Running:' /tmp/mysql_s.log|awk -F : '{print $2}'|sed 's/ //g'`

        y2=`grep 'Slave_SQL_Running:' /tmp/mysql_s.log|awk -F : '{print $2}'|sed 's/ //g'`

        if [ $y1 == "Yes" ] && [ $y2 == "Yes" ]

        then

            echo "slave status good."

        else

            echo "slave down."

        fi

    fi

fi

 

25、写一个脚本判断你的Linux服务器里是否开启web服务?(监听80端口)如果开启了,请判断出跑的是什么服务,是httpd呢还是nginx又或者是其他的什么?

#!/bin/bash

#

if `netstat -an | grep '^tcp' | awk '{print$4}'| grep -q '80$'`;then

   echo "Web Service:`lsof -i:80 | awk '{print$1}' | grep -v 'COMMAND' | sort | uniq`"

else

   echo "There is no Web Service"

fi

 

26、批量杀进程    把当前用户下所有进程名字中含有"aming"的进程关闭。

#!/bin/bash

ps -u $USER |awk '$NF ~ /aming/ {print $1}'|xargs kill 

 

27、用shell实现,以并发进程的形式将mysql数据库所有的表备份到当前目录,并把所有的表压缩到一个压缩包文件里。

 

假设数据库名字为mydb,用户名为aming,密码为passwd。

 

提示: 在shell中加上&可以将命令丢到后台,从而可以同时执行多条命令达到并发的效果。

#!/bin/bash

pre=`date +%F` 

for d in `mysql -uaming -ppasswd mydb -e "show tables"|grep -v 'Tables_in_'`

do

    mysqldump -uaming -ppasswd mydb $d > $d.sql &

done

tar czf $pre.tar.gz *.sql 

rm -f *.sql 

 

 

28、有两个文件a.txt和b.txt,需求是,把a.txt中有的并且b.txt中没有的行找出来,并写入到c.txt,然后计算c.txt文件的行数。

#!/bin/bash

n=`wc -l a.txt|awk '{print $1}'`

[ -f c.txt ] && rm -f c.txt

for i in `seq 1 $n`

do

    l=`sed -n "$i"p a.txt`

    if ! grep -q "^$l$" b.txt

    then

    echo $l >>c.txt

    fi

done

wc -l c.txt

或者用grep实现

grep -vwf b.txt a.txt > c.txt; wc -l c.txt

 

29、题目如下:

a=0.5  b=3  c=a*b   求c的值

#!/bin/bash

a=0.5

b=3

c=`echo "scale=1;$a*$b"|bc`

echo $c

 

30、需求是,把所有的成员平均得分成若干个小组。这里,我会提供一个人员列表,比如成员有50人,需要分成7个小组,要求随机性,每次和每次分组的结构应该不一致。

假设成员列表文件为members.txt

#!/bin/bash

f=members.txt

n=`wc -l $f|awk '{print $1}'`

 

get_n()

{

    l=`echo $1|wc -c`

    n1=$RANDOM

    n2=$[$n1+$l]

    g_id=$[$n1%7]

    if [ $g_id -eq 0 ]

    then

g_id=7

    fi

    echo $g_id

}

 

for i in `seq 1 7`

do

    [ -f n_$i.txt ] && rm -f n_$i.txt

done

 

for i in `seq 1 $n`

do

    name=`sed -n "$i"p $f`

    g=`get_n $name`

    echo $name >> n_$g.txt

done

 

nu(){

    wc -l $1|awk '{print $1}'

}

 

max(){

    ma=0

    for i in `seq 1 7`

    do

n=`nu n_$i.txt`

if [ $n -gt $ma ]

then

    ma=$n

fi

    done

    echo $ma

}

 

min(){

    mi=50

    for i in `seq 1 7`

    do

n=`nu n_$i.txt`

if [ $n -lt $mi ]

then

    mi=$n

fi

    done

    echo $mi

}

 

ini_min=1

 

while [ $ini_min -le 7 ]

do

    m1=`max`

    m2=`min`

    ini_min=m2

    for i in `seq 1 7`

    do

n=`nu n_$i.txt`

if [ $n -eq $m1 ]

then

    f1=n_$i.txt

elif [ $n -eq $m2 ]

then

    f2=n_$i.txt

fi

    done

    name=`tail -n1 $f1`

    echo $name >> $f2

    sed -i "/$name/d" $f1

    ini_min=$[$ini_min+1]

done

 

for i in `seq 1 7`

do

    echo "$i 组成员有:"

    cat n_$i.txt

    echo

done

 

31、将文件内所有的单词的重复次数计算出来,只需要列出重复次数最多的10个单词。

假设文档名字叫做a.txt

sed 's/[^a-zA-Z]/ /g' a.txt|xargs -n1 |sort |uniq -c |sort -nr |head

 

32、设计一个shell程序,在每月第一天备份并压缩/etc目录的所有内容,存放在/root/bak目录里,且文件名为如下形式"yymmdd_etc.tar.gz",yy为年,mm为月,dd为日。

#!/bin/sh 

if [ -d /root/bak ]

then

    mkdir /root/bak

fi

prefix=`date +%y%m%d`

d=`date +%m`

if [ $d == "01" ]

then

    cd /etc/

    tar czf  /root/bak/$prefix_etc.tar.gz ./

fi

 

33、在文本文档1.txt第5行后面增加如下内容:

# This is a test file.

# Test insert line into this file.

答  : sed -i "5a # This is a test file.\n# Test insert line into this file." 1.txt

 

34、写一个shell脚本。提示你输入一个暂停的数字,然后从1打印到该数字。然后询问是否继续。继续的话在输入个在数字 接着打印。不继续退出。
 

例:如果输入的是5,打印1 2 3 4 5  然后继续 输入15   然后打印 6 7 ...14 15 依此类推。

#!/bin/bash

read -p "请输入您想要暂停的数字:" number_1

for i in `seq 1 $number_1`;

do

        echo $i

done

read -p "是否继续输入数字?" a

if [ $a == "yes" ];then

        read -p "请继续输入您想要暂停的数字:" number_2

        number_3=$[$number_1+1]

        if [ $number_2 -gt $number_1 ];then

                for h in `seq $number_3 $number_2`;

                do

                        echo $h

                done

        else

                echo "输入数字错误,请输入大于的数字!"

        fi

else

        exit

fi

 

35、已知nginx访问的日志文件在/usr/local/nginx/logs/access.log内

请统计下早上10点到12点 来访ip最多的是哪个?

 

日志样例:

111.199.186.68 - [15/Sep/2017:09:58:37 +0800]  "//plugin.php?id=security:job" 200 "POST //plugin.php?id=security:job HTTP/1.1""http://a.lishiming.net/forum.php?mod=viewthread&tid=11338&extra=page%3D1%26filter%3Dauthor%26orderby%3Ddateline" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3141.7 Safari/537.36" "0.516"

203.208.60.208 - [15/Sep/2017:09:58:46 +0800] "/misc.php?mod=patch&action=ipnotice&_r=0.05560809863330207&inajax=1&ajaxtarget=ip_notice" 200 "GET /misc.php?mod=patch&action=ipnotice&_r=0.05560809863330207&inajax=1&ajaxtarget=ip_notice HTTP/1.1""http://a.lishiming.net/forum.php?mod=forumdisplay&fid=65&filter=author&orderby=dateline" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3141.7 Safari/537.36" "0.065"

答  : grep '15/Sep/2017:1[0-2]:[0-5][0-9]:' /usr/local/nginx/logs/access.log|awk '{print $1}'|sort -n|uniq -c |tail -n1

 

36、一个同学提到一个问题,他不小心用iptables规则把sshd端口22给封掉了,结果不能远程登陆,要想解决这问题,还要去机房,登陆真机去删除这规则。 问题来了,要写个监控脚本,监控iptables规则是否封掉了22端口,如果封掉了,给打开。 写好脚本,放到任务计划里,每分钟执行一次。

#!/bin/bash

# check sshd port drop

/sbin/iptables -nvL --line-number|grep "dpt:22"|awk -F ' ' '{print $4}' > /tmp/drop.txt

i=`cat /tmp/drop.txt|head -n 1|egrep -iE "DROP|REJECT"|wc -l`

if [ $i -gt 0 ]

then

    /sbin/iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT

fi

 

37、需求:将用户家目录(考虑到执行脚本的用户可能是普通用户也可能是root)下面小于5KB的文件打包成tar.gz的压缩包,并以当前日期为文件名前缀,例如今天打包的文件为2017-09-14.tar.gz。

#!/bin/bash

t=`date +%F`

cd $HOME

tar czf $t.tar.gz `find . -type f -size -5k`

 

38、写一个shell脚本,通过curl -I 返回的状态码来判定所访问的网站是否正常。比如,当状态码为200时,才算正常。

#/bin/bash

url="http://www.apelearn.com/index.php"

sta=`curl -I $url 2>/dev/null |head -1 |awk '{print $2}'`

if [ $sta != "200" ]

then

    python /usr/local/sbin/mail.py [email protected] "$url down." "$url down"

fi

 

39、1 每10分钟检测一次指定网卡的流量

2 如果流量为0,则重启网卡

#!/bin/bash

LANG=en

n1=`sar -n DEV 1 60 |grep eth0 |grep -i average|awk '{print $5}'|sed 's/\.//g'`

n2=`sar -n DEV 1 60 |grep eth0 |grep -i average|awk '{print $6}'|sed 's/\.//g'`

if [ $n1 == "000" ] && [ $n2 == "000" ]

then

    ifdown eth0

    ifup eth0

fi

然后写个cron,10分钟执行一次

 

40、用shell脚本判断输入的日期是否合法。就是判断日期是都是真实的日期,比如20170110就是合法日期,20171332就不合法。

#!/bin/bash

#check date

if [ $# -ne 1 ] || [ ${#1} -ne 8 ]

then

    echo "Usage: bash $0 yyyymmdd"

    exit 1

fi

datem=$1

year=${datem:0:4}

month=${datem:4:2}

day=${datem:6:2}

if echo $day|grep -q '^0'

then

    day=`echo $day |sed 's/^0//'`

fi

if cal $month $year >/dev/null 2>/dev/null

then

    daym=`cal $month $year|egrep -v "$year|Su"|grep -w "$day"`

    if [ "$daym" != "" ]

    then

        echo ok

    else

        echo "Error: Please input a wright date."

    exit 1

    fi

else

    echo "Error: Please input a wright date."

    exit 1

fi

 

41、先判断是否安装http和mysql,没有安装进行安装,安装了检查是否启动服务,若没有启动则需要启动服务。

 

说明:操作系统为centos6,httpd和mysql全部为rpm包安装。

#!/bin/bash

if_install()

{

    n=`rpm -qa|grep -cw "$1"`

    if [ $n -eq 0 ]

    then

    echo "$1 not install."

    yum install -y $1

    else

    echo "$1 installed."

    fi

}

if_install httpd

if_install mysql-server

chk_ser()

{

    p_n=`ps -C "$1" --no-heading |wc -l`

    if [ $p_n -eq 0 ]

    then

    echo "$1 not start."

    /etc/init.d/$1 start

    else

    echo "$1 started."

    fi

}

chk_httpd

chk_mysqld

 

42、写一个脚本产生随机3位的数字,并且可以根据用户的输入参数来判断输出几组。 比如,脚本名字为 number3.sh。
执行方法:
bash  number3.sh  
直接产生一组3位数字。
bash number3.sh 10  
插上10组3位数字。

思路: 可以使用echo $RANDOM获取一个随机数字,然后再除以10,取余获取0-9随机数字,三次运算获得一组。

#!/bin/bash

get_a_num() {
    n=$[$RANDOM%10]
    echo $n
}

get_numbers() {
    for i in 1 2 3; do
        a[$i]=`get_a_num`
    done
    echo ${a[@]}
}

if [ -n "$1" ]; then
    m=`echo $1|sed 's/[0-9]//g'`
    if [ -n "$m" ]; then
        echo "Useage bash $0 n, n is a number, example: bash $0 5"
        exit
    else
        for i in `seq 1 $1`
        do
            get_numbers
        done
    fi
else
    get_numbers

fi

 

43、写一个getinterface.sh 脚本可以接受选项[i,I],完成下面任务:

1)使用一下形式:getinterface.sh [-i interface | -I ip]

2)当用户使用-i选项时,显示指定网卡的IP地址;当用户使用-I选项时,显示其指定ip所属的网卡。

例:sh getinterface.sh -i eth0

       sh getinterface.sh -I 192.168.0.1

 

3)当用户使用除[-i | -I]选项时,显示[-i interface | -I ip]此信息。

4)当用户指定信息不符合时,显示错误。(比如指定的eth0没有,而是eth1时)

#!/bin/bash

ip add |awk -F ":" '$1 ~ /^[1-9]/ {print $2}'|sed 's/ //g' > /tmp/eths.txt

[ -f /tmp/eth_ip.log ] && rm -f /tmp/eth_ip.log

for eth in `cat /tmp/eths.txt`

do

    ip=`ip add |grep -A2 ": $eth" |grep inet |awk '{print $2}' |cut -d '/' -f 1`

    echo "$eth:$ip" >> /tmp/eth_ip.log

done

 

useage()

{

    echo "Please useage: $0 -i 网卡名字 or $0 -I ip地址"

}

 

wrong_eth()

{

    if ! grep -q "$1" /tmp/eth_ip.log

    then

        echo "请指定正确的网卡名字"

    exit

    fi

}

 

wrong_ip()

{

    if ! grep -qw "$1" /tmp/eth_ip.log

    then

        echo "请指定正确的ip地址"

    exit

    fi

}

 

if [ $# -ne 2 ]

then

    useage

    exit

fi

 

case $1 in

    -i)

    wrong_eth $2 

    grep $2 /tmp/eth_ip.log |awk -F ':' '{print $2}'

    ;;

 

    -I)

    wrong_ip $2

    grep $2 /tmp/eth_ip.log |awk -F ':' '{print $1}'

    ;;

 

    *)

    useage

    exit

esac

 

44、比如1.txt内容
1
2
3
4
5
6
7

处理后应该是
1 2 3
4 5 6
7

sed 'N;N;s/\n/ /g' 1.txt

 

45、先普及一小段知识,我们用ps aux可以查看到进程的PID,而每个PID都会在/proc内产生。如果查看到的pid而proc内是没有的,则是进程被人修改了,这就代表你的系统很有可能已经被入侵过了。

 

请大家用上面知识编写一个shell,定期检查下自己的系统是否被人入侵过。

#!/bin/bash

ps aux|awk '/[0-9]/ {print $2}'|while read pid

do

    result=`find /proc/ -maxdepth 1 -type d -name "$pid"`

    if [ -z $result ]; then

        echo "$pid abnormal!"

    fi

done

 

46、1 编写一个名为chname的程序,将当前目录下所有的.txt文件更名为.doc文件。

 

2 编写一个名为chuser的程序,执行中每隔5分钟检查指定的用户是否登录系统,用户名从命令行输入;如果指定的用户已经登录,则显示相关信息。

#!/bin/bash

find . -type f -name "*.txt" > /tmp/txt.list

for f in `cat /tmp/txt.list`

do

    n=`echo $f|sed -r 's/(.*)\.txt/\1/'`

    echo "mv $f $n.doc"

done

 

#!/bin/bash

read -p "Please input the username: " user

while :

do

    if who | grep -qw $user

    then

        echo $user login.

    else

        echo $user not login.

    fi

    sleep 300

done

 

47、1 编写一个名为ifuser的程序,它执行时带用户名作为命令行参数,判断该用户是否已经在系统中登录,并给出相关信息。

 

2 编写一个名为menu的程序,实现简单的弹出式菜单功能,用户能根据显示的菜单项从键盘选择执行对应的命令。

1   #!/bin/bash

read -p "Please input the username: " user

if who | grep -qw $user

then

    echo $user is online.

else

    echo $user not online.

fi

 

2. 

#!/bin/bash

function message()

{

    echo "0. w"

    echo "1. ls"

    echo "2.quit"

    read -p "Please input parameter: " Par

}

message

while [ $Par -ne '2' ] ; do

    case $Par in

    0)

        w

        ;;

    1)

        ls

        ;;

    2)

        exit

        ;;

    *)

        echo "Unkown command"

        ;;

  esac

  message

done

 

48、1 编写一个名为iffile程序,它执行时判断/bin目录下date文件是否存在?

 

2 编写一个名为greet的问候程序,它执行时能根据系统当前的时间向用户输出问候信息。设从半夜到中午为早晨,中午到下午六点为下午,下午六点到半夜为晚上。

#!/bin/bash

if [ -f /bin/date  ] 

then

    echo "/bin/date file exist."

else

    echo "/bin/date not exist."

fi

#!/bin/bash

h=`date +%H`

if [ $h -ge 0 ] && [ $h -lt 12 ]

then

    echo "Good morning."

elif [ $h -ge 12 ] && [ $h -lt 18 ]

then

    echo "Good afternoon."

else

    echo "Good evening."

fi

 

49、输入一串随机数字,然后按千分位输出。

 

比如输入数字串为“123456789”,输出为123,456,789

#!/bin/bash

read -p "输入一串数字:" num

v=`echo $num|sed 's/[0-9]//g'`

if [ -n "$v" ]

then

    echo "请输入纯数字."

    exit

fi

length=${#num}

len=0

sum=''

for i in $(seq 1 $length)

do

        len=$[$len+1]

        if [[ $len == 3 ]]

        then

                sum=','${num:$[0-$i]:1}$sum

                len=0

        else

                sum=${num:$[0-$i]:1}$sum

        fi

done

if [[ -n $(echo $sum | grep '^,' ) ]]

then

        echo ${sum:1}

else

        echo $sum

fi

上面这个答案比较复杂,下面再来一个sed的

#!/bin/bash

read -p "输入一串数字:" num

v=`echo $num|sed 's/[0-9]//g'`

if [ -n "$v" ]

then

    echo "请输入纯数字."

    exit

fi

echo $num|sed -r '{:number;s/([0-9]+)([0-9]{3})/\1,\2/;t number}'

 

50、检查错误 

#!/bin/bash
sh -n $1 2>/tmp/err
if [ $? -eq "0" ]
then
    echo "The script is OK."
else
    cat /tmp/err
    read -p "Please inpupt Q/q to exit, or others to edit it by vim. " n
    if [ -z $n ]
    then
        vim $1
        exit
    fi
    if [ $n == "q" -o $n == "Q" ]
    then
        exit
    else
        vim $1
        exit
    fi

fi

 

51、一个网站,使用了cdn,全国各地有几十个节点。需要你写一个shell脚本来监控各个节点是否正常。

 

假如

1 监控的url为www.aming.com/index.php

2 源站ip为88.88.88.88

3 以及各个节点ip列表文件为/tmp/ip.txt

#!/bin/bash

url="www.aming.com/index.php"

s_ip="88.88.88.88"

curl -x $s_ip:80 $url > /tmp/source.html 2>/dev/null

for ip in `cat /tmp/ip.txt`

do

    curl -x $ip:80 $url 2>/dev/null >/tmp/$ip.html

    [ -f /tmp/$ip.diff ] && rm -f /tmp/$ip.diff

    touch /tmp/$ip.diff

    diff /tmp/source.html /tmp/$ip.html > /tmp/$ip.diff 2>/dev/null

    n=`wc -l /tmp/$ip.diff|awk '{print $1}'`

    if [ $n -lt 0 ]

    then

        echo "node $ip sth wrong."

    fi

done

 

52、写一个脚本:
判断当前主机的CPU生产商,其信息在/proc/cpuinfo文件中vendor id一行中。
如果其生产商为AuthenticAMD,就显示其为AMD公司;
如果其生产商为GenuineIntel,就显示其为Intel公司;
否则,就说其为非主流公司。

#!/bin/bash

m=`cat /proc/cpuinfo |grep vendor_id|awk  -F":" '{print $2}'|tail -1`

if [ $m == "GenuineIntel" ]

then

     echo "cpu is 英特尔"

elif [ $m == "AuthenticAMD" ]

then

     echo "cpu is AMD"

else

     echo "cpu is 非主流"

fi

 

53、破解字符串

说明:题目中最后一个字符串少写了一位,应该是890684ba

 

#!/bin/bash

for n in {0..32767}

do

        MD5=`echo $n | md5sum | cut -c 1-8`

        if [ "$MD5" == "$1" ];then

            echo "$n $c "

            break

        fi

done

 

54、用shell写一个监控服务器cpu使用率的监控脚本。

 

思路:用top -bn1 命令,取当前空闲cpu百份比值(只取整数部分),然后用100去剑这个数值。

 

55、脚本添加了只要使用率超过80%就会发一封报警邮件,脚本每隔5秒钟执行一次! #! /bin/bash

##monitoring the cpu value if alwasy higher or not

##written by zhdya_20171012

while :

do

          sum=0

          for i in `top -bn1 | awk '{print $9}'| sed -n '8,$'p | cut -d "." -f 1`

          do

                  sum=$[$sum+$i]

          done

                   echo "the cpu already used $sum%"

                     if [ $sum -gt 80 ]

                     then

                                echo "the cpu already used $sum%, pls pay attention.."                                          ##sendmail

                      fi

        sleep 5

done

 

56、说明:本shell题目是一个网友在公众号中提问的,正好利用这个每日习题的机会拿出来让大家一起做一做。

 

给出一个进程PID,打印出该进程下面的子进程以及子进程下面的所有子进程。(只需要考虑子进程的子进程,再往深层次则不考虑)

 

57、用shell写一个监控服务器cpu使用率的监控脚本。

 

思路:用top -bn1 命令,取当前空闲cpu百份比值(只取整数部分),然后用100去剑这个数值。

#!/bin/bash

while :

do

    idle=`top -bn1 |sed -n '3p' |awk '{print $5}'|cut -d . -f1`

    use=$[100-$idle]

    if [ $use -gt 90 ]

    then 

echo "cpu use percent too high."

#发邮件省略

    fi

    sleep 10

done

 

58、上一篇文章我们介绍了命名管道FIFO,利用里面的知识点,实现这个需求。

需求背景:

领导要求小明备份数据库服务器里面的100个库(数据量在几十到几百G),需要以最快的时间完成(5小时内),并且不能影响服务器性能。

 

需求分析:

由于数据量比较大,单个库备份时间少则10几分钟,多则几个小时,我们算平均每个库30分钟,若一个库一个库的去备份,则需要3000分钟,相当于50个小时。很明显不可取。但全部丢到后台去备份,100个并发,数据库服务器也无法承受。所以,需要写一个脚本,能够控制并发数就可以实现了。

#!/bin/sh

##假设100个库的名字存到了一个文件里,文件名字为/tmp/databases.list

##其中备份数据库用了mysqldump,这里你可以换成xtrabackup,更快

 

function bak_data {

    dbname=$1

    d=`date +%y%d`

    mysqldump -uroot -pxxxxx $dbname > /backup/$1.$d

}

 

mkfifo $tmp_fifofile

exec 1000<>$tmp_fifofile

rm -f $tmp_fifofile

 

thread=10

for ((i=0;i<$thread;i++));

do

    echo >&1000

done

 

for d in `cat /tmp/databases.list`

do

    read -u6

    {

        bak_data $d 

        echo >&1000

    } & 

done

wait

exec 1000>&-

 

59、我们使用的云主机,购买一块云盘后,默认并不是挂载状态的,用shell写一个脚本,只要把盘符和挂载点以参数的形式提供给脚本,该脚本就可以自动格式化、挂载。

要求:

1 不用分区,直接格式化

2 格式化为ext4文件系统类型

#!/bin/bash

echo "Useage $0 盘符 挂载点, 如: $0 /dev/xvdb /data"

if [ $# -ne 2 ]

then

    exit

fi

 

if [ ! -b $1 ]

then 

    echo "你提供的盘符不正确,请检查后再操作"

    exit 1

fi

mkfs -t ext4 $1

if [ ! -d $2 ] ;then

        mkdir -p $2

fi

n=`egrep " $2 " /etc/fstab|wc -l`

if [ $n -eq 0 ]

then

    echo "$1              $2                      ext4   defaults  0  0" >> /etc/fstab

    mount -a

else

    mount $1 $2

    echo "配置文件/etc/fstab中已经存在挂载点$2,请检查一下."

fi

 

60、自动封/解封ip

需求背景:

discuz论坛,每天有很多注册机注册的用户,然后发垃圾广告帖子。虽然使用了一些插件但没有效果。分析访问日志,发现有几个ip访问量特别大,所以想到可以写个shell脚本,通过分析访问日志,把访问量大的ip直接封掉。

但是这个脚本很有可能误伤,所以还需要考虑到自动解封这些ip。

思路:

1 可以每分钟分析1次访问日志,设定一个阈值,把访问量大的ip用iptables封掉80端口

 

2 每20分钟检测一次已经被封ip的请求数据包数量,设定阈值,把没有请求的或者请求量很小的解封

#! /bin/bash

## To block the ip of bad requesting.

## Writen by aming 2017-11-18.

log="/data/logs/www.xxx.com.log"

tmpdir="/tmp/badip"

#白名单ip,不应该被封

goodip="27.133.28.101"

 

[ -d $tmpdir ] || mkdir -p $tmpdir

t=`date -d "-1 min"  +%Y:%H:%M`

#截取一分钟以前的日志

grep "$t:" $log > $tmpdir/last_min.log

#把一分钟内日志条数大于120的标记为不正常的请求

awk '{print $1}' $tmpdir/last_min.log |sort -n |uniq -c |sort -n |tail |awk '$1>120 {print $2}'|grep -v "$good_ip"> $tmpdir/bad.ip

d3=`date +%M`

#每隔20分钟解封一次ip

if [ $d3 -eq "20" ] || [ $d3 -eq "40" ] || [ $d3 -eq "00" ]; then

        /sbin/iptables -nvL INPUT|grep 'DROP' |awk '$1<10 {print $8}'>$tmpdir/good.ip

        if [ -s $tmpdir/good.ip ]; then

        for ip in `cat $tmpdir/good.ip`

        do

                /sbin/iptables -D INPUT -p tcp --dport 80 -s $ip -j DROP

                d4=`date +%Y%m%d-%H:%M`

                echo "$d4 $ip unblock" >>$tmpdir/unblock.ip

        done

        fi

        #解封后,再把iptables的计数器清零

        /sbin/iptables -Z INPUT

fi

if [ -s $tmpdir/bad.ip ] ; then

    for ip in `cat $tmpdir/bad.ip`

    do

        /sbin/iptables -A INPUT -p tcp --dport 80 -s $ip -j DROP

        d4=`date +%Y%m%d-%H:%M`

        echo "$d4 $ip block" >>$tmpdir/block.ip

    done

fi

 

61、写个shell脚本,能够实现一键安装并配置samba服务,执行该脚本时需要带一个参数,为共享的目录,目录可以不存在,若不存在,需要脚本自动创建。

#!/bin/bash

is_samba_installed=`rpm -qa|grep samba|wc -l`

if [ $is_samba_installed != 0 ]

then

    echo "You had already installed Samba."

    exit 0

fi

echo "It will install Samba."

sleep 1

cnfdir="/etc/samba/smb.conf"

chkok(){

    if [ $? != 0 ]

    then

        echo "Error, Please try again."

        exit 1

    fi

}

yum install -y samba

chkok

sed -i 's/MYGROUP/WORKGROUP/' $cnfdir

sed -i 's/user/share/' $cnfdir

sed -i '$a\[fish]' $cnfdir

if [ -d $1 ]

then

    cd $1

    echo "test" > test.txt

    sed -i '$a\[fish]\n\tcomment = Share All\n\tpath = "'$1'"\n\tbrowseable = yes\n\tpublic = yes\n\twritable = no' $cnfdir

else

    mkdir $1

    cd $1

    echo "test" > test.txt

    sed -i '$a\[fish]\n\tcomment = Share All\n\tpath = "'$1'"\n\tbrowseable = yes\n\tpublic = yes\n\twritable = no' $cnfdir

fi

/etc/init.d/smb start

chkok

echo "Please input [\\sambaIP\sharename] to access the share dir."

 

62、用shell写一个脚本,实现一键管理docker容器,比如启动/关闭/删除容器等操作。

要求:

1 脚本支持启动全部容器、关闭全部容器、删除全部容器

 

2 需要提示用户如何使用该脚本,需给出范例

#! /bin/bash

##start,restart,delete the docker containers

##written by zhdya_20171114

list=`docker ps -a |awk '{print $2}'| grep -v 'ID'`

echo "======================================="

echo -e "pls check the follow list of container: \n$list"

read -p "pls choose an action which you want!<1.start 2.stop 3.rm > " act

echo "======================================"

echo -e "stop\nstart\nrm\nrmi" > /tmp/docker.txt 

##judge if input the words or not!

if [ -z $act ]

then

        echo "you type was wrong,pls just input "start"."stop"."rm"."rmi"."

        exit

fi

##judge if input a wrong words!!

if grep -wq $act /tmp/docker.txt

then

        case $act in

        start)

                docker start $(docker ps -a | awk '{ print $1}' | tail -n +2)

                echo "already start all of container,pls checking it.."

        ;;

        stop)

                docker stop $(docker ps -a | awk '{ print $1}' | tail -n +2)

                echo "already restart all of container,pls checking it.."

        ;;

        rm)

                docker rm $(docker ps -a | awk '{ print $1}' | tail -n +2)

                echo "already rm all of container,pls checking it.."

        ;;

        *)

                docker rmi $(docker images | awk '{print $3}' |tail -n +2)

                echo "already rm all of container,pls checking it.."

        esac

else

        echo "you type was wrong,pls just input "start"."stop"."rm"."rmi"."

fi

 

63、用shell脚本实现,部署mysql主从架构。

思路是这样的:

 

1)master.sh脚本用来安装master的mysql

 

2)然后通过expect脚本+rsync工具把slave.sh脚本、/etc/my.cnf、 /etc/init.d/mysqld 还有mysqldump下来的all.sql,以及在master下载下来的mysql二进制安装包传到slave上

 

3)通过expect脚本来运行slave.sh的脚本来安装,并且配置好主从,期间,用slave.tmp来记录master机子的binlog的状态,以便于传到slave后用命令添加进去。

cp_slave.expect

#!/usr/bin/expect

set user [lindex $argv 0]

set host [lindex $argv 1]

set passwd [lindex $argv 2]

set file [lindex $argv 3]

spawn rsync -avzP $file $user@$host:/tmp

set timeout 600

expect {

"yes/no" { send "yes\r"}

"password:" { send "$passwd\r" }

}

expect eof

 

ins_rsync.expect

#!/usr/bin/expect

set user [lindex $argv 0]

set host [lindex $argv 1]

set passwd [lindex $argv 2]

spawn ssh $user@$host

expect {

 "yes/no" { send "yes\r";exp_continue}

 "password:" { send "$passwd\r" }

}

expect "]*"

send "yum install -y rsync\rexit\r"

interact

 

slave.expect

#!/usr/bin/expect

set host [lindex $argv 0]

set passwd [lindex $argv 1]

set cm [lindex $argv 2]

spawn ssh root@$host

expect {

"yes/no" { send "yes\r"}

"password:" { send "$passwd\r" }

}

expect "]*"

send "$cm\rexit\r"

interact

 

slave.sh

#!/bin/bash

####this is for building slave script

##by lv.

####master ip address

mas_ip=192.168.47.24

###mysql password conf

my_passwd=hd8832508

####replication user and password

rp_user=hd

rp_passwd=hd8832508

###check ok

check(){

  if [ $? != 0 ]

  then

     echo "error,please check log."

     exit 1

  fi

}

##close seliux

sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config

selinux_s=`getenforce`

if [ $selinux_s == "Enforcing"  -o $selinux_s == "enforcing" ]

then

    setenforce 0

fi

##close iptables

iptables-save > /etc/sysconfig/iptables_`date +%s`

iptables -F

service iptables save

##install the mirror.aliyun.com

cd /etc/yum.repos.d/

  if rpm -qa |grep epel-release >/dev/null

  then

    rpm -e epel-release

   fi

if [ -f epel.repo ]

then

  /bin/mv epel.repo epel.repo.bak

fi

yum install -y wget

  if [ -f CentOS-Base.repo ]

   then

    /bin/mv CentOS-Base.repo CentOS-Base.repo.bak

    wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo

     wget http://mirrors.aliyun.com/repo/epel-6.repo -O /etc/yum.repos.d/epel.repo

  fi

yum clean all

yum makecache

#first to update datetime

[ `rpm -qa |grep ntpdate|wc -l` -eq 1 ] || yum install -y ntpdate

ntpdate 0.openwrt.pool.ntp.org 2>&1 >/dev/null;clock -w

###install lib software

syum(){

  if ! rpm -qa|grep -q $1

    then

      yum install -y $1

     check

  else

    echo "$1 is already installed"

fi

}

## install some packges for the first on setup.

for p in gcc perl perl-devel libaio libaio-devel pcre-devel zlib-devel cmake glibc pcre compat-libstdc++-33

do

   syum $p

done

###check file is already in tmp 

if [ ! -f /tmp/my.cnf ] && [ ! -f /tmp/mysqld ] && [ ! -f /tmp/mysql-* ] && [ ! -f /tmp/slave.tmp ]

then

   echo "error,please try to sync again"

   exit 1

fi

mysql=`ls /tmp |grep tar.gz`

version=`echo /tmp/$mysql|awk -F - '{print $2}'|cut -d. -f2`

######install mysql

cd /tmp

tar -zxf $mysql

mv `echo $mysql|sed 's/.tar.gz//g'` /usr/local/mysql

cd /usr/local/mysql

if ! grep "^mysql:" /etc/passwd

then

   useradd -s /sbin/nologin -M mysql

   check

fi

[ -d /data/mysql ] && /bin/mv /data/mysql /data/mysql_`date +%s`

mkdir -p /data/mysql

chown -R mysql:mysql /data/mysql

###initialize

case $version in

      1)

    /usr/local/mysql/scripts/mysql_install_db --user=mysql --datadir=/data/mysql

     check

     sed -i '/^server-id/'d /tmp/my.cnf

     check

     sed -i '/\[mysqld\]/a\server-id=2' /tmp/my.cnf

     check

     ;;

     6)

     /usr/local/mysql/scripts/mysql_install_db --user=mysql --datadir=/data/mysql

      check

     sed -i '/^server_id/'d /tmp/my.cnf

     check

     sed -i '/\[mysqld\]/a\server_id = 2' /tmp/my.cnf

     check

      ;;

     7)

      pswd5_7=`/usr/local/mysql/bin/mysqld --user=mysql --datadir=/data/mysql --initialize 2>&1 |sed -r -n '/localhost: /p'|sed 's/.* //g'`

     /usr/local/mysql/bin/mysql_ssl_rsa_setup --datadir=/data/mysql

     check

     sed -i '/^server_id/'d /tmp/my.cnf

     check

     sed -i '/\[mysqld\]/a\server_id = 2' /tmp/my.cnf

     check

     ;;

  esac

###cp conf file

/bin/cp -rf /tmp/my.cnf /etc/my.cnf

check

/bin/cp -rf /tmp/mysqld /etc/init.d/

check

chmod 755 /etc/init.d/mysqld

chkconfig --add mysqld

chkconfig mysqld on

service mysqld start

check

####change mysql password

if [ $version -eq 7 ]

then

    /usr/local/mysql/bin/mysql -uroot -p$pswd5_7 --connect-expired-password -e "set password=password('$my_passwd');"

    check

else

   /usr/local/mysql/bin/mysql -uroot -e "set password=password('$my_passwd');"

   check

fi

###input date

if [ -f /tmp/all.sql ]

then

   /usr/local/mysql/bin/mysql -uroot -p$my_passwd < /tmp/all.sql

   check

else

   echo "date error."

   exit 1

fi

######binlog

slave_bin=`grep "mysql-bin" /tmp/slave.tmp`

slave_pos=`grep '^[0-9]' /tmp/slave.tmp`

###stop slave

/usr/local/mysql/bin/mysql -uroot -p$my_passwd -e "stop slave;"

check

###configure slave

/usr/local/mysql/bin/mysql -uroot -p$my_passwd -e "change master to master_host='$mas_ip',master_port=3306,master_user='$rp_user',master_password='$rp_passwd',master_log_file='$slave_bin',master_log_pos=$slave_pos;"

check

###start slave

/usr/local/mysql/bin/mysql -uroot -p$my_passwd -e "start slave;"

check

###check repecation status

show=`/usr/local/mysql/bin/mysql -uroot -p$my_passwd -e "show slave status\G;"|grep 'Slave_IO_Running:'`

slaveIO=`echo $show|awk -F':' '{print $2}'`

Slave_SQL=`echo $show|awk -F':' '{print $2}'`

 

if [ $slaveIO == Yes ] && [$Slave_SQL == Yes ]

then

  echo "mysql repliation is start"

  /bin/rm -rf /tmp/all.sql /tmp/$mysql /tmp/mysqld /tmp/my.cnf /tmp/slave.tmp

else

  echo "error,please check the log."

fi

master.sh

#!/bin/bash

#####this is building mysql replication###

##by lv.

ml=`pwd`

ar=`arch`

###mysql password conf

my_passwd=hd8832508

####replication user and password

rp_user=hd

rp_passwd=hd8832508

###slave conf

s_user=root

s_host=192.168.47.25

s_passwd=hd8832508

###check ok

check(){

  if [ $? != 0 ]

  then

     echo "error,please check log."

     exit 1

  fi

}

####check the file is exist

for wj in $ml/cp_slave.expect $ml/ins_rsync.expect $ml/slave.expect $ml/slave.sh

do

   if [ ! -f $wj ]

   then

    echo "error,your miss $wj file."

    exit 1

   else

     /bin/chmod +x $wj

     check

   fi

done

##close seliux

sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config

selinux_s=`getenforce`

if [ $selinux_s == "Enforcing"  -o $selinux_s == "enforcing" ]

then

    setenforce 0

fi

##close iptables

iptables-save > /etc/sysconfig/iptables_`date +%s`

iptables -F

service iptables save

##install the mirror.aliyun.com

aliyun(){

cd /etc/yum.repos.d/

  if rpm -qa |grep epel-release >/dev/null

  then

    rpm -e epel-release

   fi

if [ -f epel.repo ]

then

  /bin/mv epel.repo epel.repo.bak

fi

  yum install -y wget

  if [ -f CentOS-Base.repo ]

   then

    /bin/mv CentOS-Base.repo CentOS-Base.repo.bak

    wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo

     wget http://mirrors.aliyun.com/repo/epel-6.repo -O /etc/yum.repos.d/epel.repo

  fi

yum clean all

yum makecache

}

if [ `grep "aliyun.com" /etc/yum.repos.d/CentOS-Base.repo|wc -l` -eq 0 ]

then

   aliyun

else

   echo "aliyun epel is already installed."

fi 

#first to update datetime

[ `rpm -qa |grep ntpdate|wc -l` -eq 1 ] || yum install -y ntpdate

ntpdate 0.openwrt.pool.ntp.org 2>&1 >/dev/null;clock -w

###install lib software

syum(){

  if ! rpm -qa|grep -q $1

    then

      yum install -y $1

     check

  else

    echo "$1 is already installed"  

fi

}

## install some packges for the first on setup.

for p in gcc perl perl-devel libaio libaio-devel pcre-devel zlib-devel cmake glibc pcre compat-libstdc++-33

do

   syum $p

done

###variables,fuctions

mysql_5_1=http://mirrors.sohu.com/mysql/MySQL-5.1/mysql-5.1.73-linux-$ar-glibc23.tar.gz

mysql_5_6=http://mirrors.sohu.com/mysql/MySQL-5.6/mysql-5.6.31-linux-glibc2.5-$ar.tar.gz

mysql_5_7=http://mirrors.sohu.com/mysql/MySQL-5.7/mysql-5.7.12-linux-glibc2.5-$ar.tar.gz

#######################################

conf_mysql(){

   cd /usr/local/mysql

   if ! grep "^mysql:" /etc/passwd

   then

   useradd -s /sbin/nologin -M mysql

   check

   fi

   [ -d /data/mysql ] && /bin/mv /data/mysql /data/mysql_`date +%s`

    mkdir -p /data/mysql

    chown -R mysql:mysql /data/mysql

###initialize

   case $version in

      5.1)

    ./scripts/mysql_install_db --user=mysql --datadir=/data/mysql

     check

     ;;

     5.6)

     ./scripts/mysql_install_db --user=mysql --datadir=/data/mysql

      check

      ;;

     5.7)

      pswd5_7=`./bin/mysqld --user=mysql --datadir=/data/mysql --initialize 2>&1 |sed -r -n '/localhost: /p'|sed 's/.* //g'`

     ./bin/mysql_ssl_rsa_setup --datadir=/data/mysql

     check

     ;;

  esac

}

cp_mysql(){

###my.cnf

      if [ -f  /usr/local/mysql/support-files/my-huge.cnf ]

         then

         /bin/cp -rf support-files/my-huge.cnf /etc/my.cnf

         check

 sed -i '/^\[mysqld\]$/a\datadir = /data/mysql' /etc/my.cnf

           check

         else

            /bin/cp -rf support-files/my-default.cnf /etc/my.cnf

             check

        sed -i '/^\[mysqld\]$/a\socket = /tmp/mysql.sock' /etc/my.cnf

        sed -i '/^\[mysqld\]$/a\port = 3306' /etc/my.cnf

        sed -i '/^\[mysqld\]$/a\datadir = /data/mysql' /etc/my.cnf

        check

        sed -i '/^\[mysqld\]$/a\basedir = /usr/local/mysql' /etc/my.cnf

        fi

####/etc/init.d/mysqld

     if [ $version == 5.7 ]

     then

      /bin/cp support-files/mysql.server /etc/init.d/mysqld

      check

       sed -i 's#^datadir=#datadir=/data/mysql#' /etc/init.d/mysqld

       sed -i 's#^basedir=#basedir=/usr/local/mysql#' /etc/init.d/mysqld

     check

      chmod 755 /etc/init.d/mysqld

      chkconfig --add mysqld

      chkconfig mysqld on

      service mysqld start

      check

     else

      /bin/cp support-files/mysql.server /etc/init.d/mysqld

      sed -i 's#^datadir=#datadir=/data/mysql#' /etc/init.d/mysqld

      chmod 755 /etc/init.d/mysqld

      chkconfig --add mysqld

      chkconfig mysqld on

      service mysqld start

      check

    fi

 

}

 

###install mysql

insall_mysql(){ 

echo "Chose the version of mysql."

select mysql_v in 5.1 5.6 5.7

do

    case $mysql_v in

        5.1)

            cd /usr/local/src

            [ -f ${mysql_5_1##*/} ] || wget $mysql_5_1

            tar zxf ${mysql_5_1##*/}

            check_ok

            [ -d /usr/local/mysql ] && /bin/mv /usr/local/mysql /usr/local/mysql_`date +%s`

            mv `echo ${mysql_5_1##*/}|sed 's/.tar.gz//g'` /usr/local/mysql

            check_ok

           version=5.1

            conf_mysql

            cp_mysql

        break

        ;;

    5.6)

            cd /usr/local/src

            [ -f ${mysql_5_6##*/} ] || wget $mysql_5_6

            tar zxf ${mysql_5_6##*/}

            check_ok

            [ -d /usr/local/mysql ] && /bin/mv /usr/local/mysql /usr/local/mysql_bak

            mv `echo ${mysql_5_6##*/}|sed 's/.tar.gz//g'` /usr/local/mysql

        check_ok

            version=5.6

            conf_mysql

            cp_mysql

        break

        ;;

    5.7)

            cd /usr/local/src

            [ -f ${mysql_5_7##*/} ] || wget $mysql_5_7

            tar zxf ${mysql_5_7##*/}

            check_ok

            [ -d /usr/local/mysql ] && /bin/mv /usr/local/mysql /usr/local/mysql_bak

            mv `echo ${mysql_5_7##*/}|sed 's/.tar.gz//g'` /usr/local/mysql

            check_ok

            version=5.7

           conf_mysql

           cp_mysql

            break

            ;;

    *)

            echo "only 1(5.1) 2(5.6) or 3(5.7) "

            exit 1

            ;;

    esac

done

}

####change mysql password

passwd_mysql(){

if [ $version == 5.7 ]

then

    /usr/local/mysql/bin/mysql -uroot -p$pswd5_7 --connect-expired-password -e "set password=password('$my_passwd');"

    check

else

   /usr/local/mysql/bin/mysql -uroot -e "set password=password('$my_passwd');"

   check

fi

}

######

if [ `ps aux|grep mysql|wc -l` -gt 1 ]

then

   echo "mysql is already start"

else

   insall_mysql

   passwd_mysql

fi

####start install slave

echo "#############################"

echo "##                         ##"

echo "##      slave install      ##"

echo "##                         ##"

echo "#############################"

##first check master tool

if ! rpm -qa|grep -q rsync 

then

  yum install -y rsync

fi

if ! rpm -qa|grep -q expect

then

  yum install -y expect

fi

###replication building for master first

if [ `ps aux|grep mysql|wc -l` -gt 1 ] && [ `grep "log_bin = mysql-bin" /etc/my.cnf|wc -l` -eq 0 ] && [ `grep "log-bin=mysql-bin" /etc/my.cnf|wc -l` -eq 0 ]

then

   /etc/init.d/mysqld stop

   check

   sed -i '/^\[mysqld\]$/a\server_id = 1' /etc/my.cnf

   sed -i '/^\[mysqld\]$/a\log_bin = mysql-bin' /etc/my.cnf

   sed -i '/^\[mysqld\]$/a\binlog_format = "MIXED"' /etc/my.cnf

    check

   /etc/init.d/mysqld start

   check

fi

master_bin=`/usr/local/mysql/bin/mysql -uroot -p$my_passwd -e "show master status \G;"|grep File|awk '{print $2}'`

master_pos=`/usr/local/mysql/bin/mysql -uroot -p$my_passwd -e "show master status \G;"|grep Position|awk '{print $2}'`

echo $master_bin >>/tmp/slave.tmp

echo $master_pos >>/tmp/slave.tmp

/usr/local/mysql/bin/mysql -uroot -p$my_passwd -e "grant replication slave on *.* to $rp_user@'$s_host' identified by '$rp_passwd';"

check

/usr/local/mysql/bin/mysql -uroot -p$my_passwd -e "flush privileges;"

check

###dump date

/usr/local/mysql/bin/mysqldump -uroot -p$my_passwd --single-transaction -A > /tmp/all.sql

check

####cp file to slave

if [ `pwd` != $ml ]

then

   cd $ml

fi

./ins_rsync.expect $s_user $s_host $s_passwd

for file in /usr/local/src/mysql-* /etc/my.cnf /etc/init.d/mysqld ./slave.sh /tmp/slave.tmp /tmp/all.sql

do

   ./cp_slave.expect $s_user $s_host $s_passwd $file

done

./slave.expect $s_host $s_passwd /tmp/slave.sh

 

64、写一个shell脚本,当我们执行时,提示要输入对方的ip和root密码,然后可以自动把本机的公钥增加到对方机器上,从而实现密钥认证。

#!/bin/bash

read -p "Input IP: " ip

ping $ip -w 2 -c 2 >> /dev/null

## 查看ip是否可用

while [ $? -ne 0 ]

do

read -p "your ip may not useable, Please Input your IP: " ip

ping $ip -w 2 -c 2 >> /dev/null

done

read -p "Input root\'s password of this host: " password

## 检查命令子函数

check_ok() {

if [ $? != 0 ]

then

echo "Error!."

exit 1

fi

}

## yum需要用到的包

myyum() {

if ! rpm -qa |grep -q "$1"

then

yum install -y $1

check_ok

else

echo $1  already installed

fi

}

for p in openssh-clients openssh expect

do

myyum $p

done

## 在主机A上创建密钥对

if [ ! -f ~/.ssh/id_rsa ] || [ ! -f ~/.ssh/id_rsa.pub ]

then

    if [ -d ~/.ssh ]

    then

        mv ~/.ssh/  ~/.ssh_old

    fi

    echo -e "\n" | ssh-keygen -t rsa -P ''

    check_ok

fi

## 传私钥给主机B

if [ ! -d /usr/local/sbin/rsync_keys ]

then

    mkdir /usr/local/sbin/rsync_keys

fi

cd /usr/local/sbin/rsync_keys

if [ -f rsync.expect ]

then

    d=`date +%F-%T`

    mv rsync.expect $d.expect

fi

#创建远程同步的expect文件

cat >  rsync.expect <

#!/usr/bin/expect

set host [lindex \$argv 0]

#主机B的密码

set passwd [lindex \$argv 1]

spawn rsync -av /root/.ssh/id_rsa.pub root@\$host:/tmp/tmp.txt

expect {

"yes/no" { send "yes\r"; exp_continue}

"password:" { send "\$passwd\r" }

}

expect eof

spawn ssh root@\$host

expect {

"password:" { send "\$passwd\r" }

}

expect "]*"                         

send "\[ -f /root/.ssh/authorized_keys \] && cat /tmp/tmp.txt >>/root/.ssh/authorized_keys \r"

expect "]*"

send "\[ -f /root/.ssh/authorized_keys \] || mkdir -p /root/.ssh/ \r"            

send "\[ -f /root/.ssh/authorized_keys \] || mv /tmp/tmp.txt /root/.ssh/authorized_keys\r"            

expect "]*"

send "chmod 700 /root/.ssh; chmod 600 /root/.ssh/authorized_keys\r"

expect "]*"

send "exit\r"

EOF

check_ok

/usr/bin/expect /usr/local/sbin/rsync_keys/rsync.expect $ip $password

echo "OK,this script is successful. ssh $ip  to test it"

 

65、写一个shell脚本,查询指定域名的过期时间,并在到期前一周,每天发一封提醒邮件。

思路: 大家可以在linux下使用命令“whois 域名”,如"whois apelearn.com",来获取该域名的一些信息。

 

提示: whois命令,需要安装jwhois包

#!/bin/bash

t1=`date +%s`

is_install_whois()

{

    which whois >/dev/null 2>/dev/null

    if [ $? -ne 0 ]

    then

        yum install -y jwhois

    fi

}

notify()

{

    e_d=`whois $1|grep 'Expiry Date'|awk '{print $4}'|cut -d 'T' -f 1`

    e_t=`date -d "$e_d" +%s`

    n=`echo "86400*7"|bc`

    e_t1=$[$e_t-$n]

    if [ $t1 -ge $e_t1 ] && [ $t1 -lt $e_t ]

    then

        /usr/local/sbin/mail2.py [email protected] "Domain $1 will be expire." "Domain $1 expire date is $e_d."

    fi

}

is_install_whois

notify aminglinux.com

 

66、至少用两种方法,批量把当前目录下面所有文件名后缀为.bak的后缀去掉,比如1.txt.bak去掉后为1.txt

答 :

假设取消的后缀为.bak

 

方法一:

for i in `ls *.bak`

do 

    mv $i `echo $i|sed 's/\.bak//g'`

done

 

方法二:

for i in `ls *.bak`

do 

    newname=`echo $i|awk -F '.bak' '{print $1}'` 

    mv $i $newname

done

 

67、在生产环境中,经常遇到tomcat无法彻底关闭,也就是说用tomcat自带shutdown.sh脚本无法将java进程完全关掉。所以,需要借助shell脚本,将进程杀死,然后再启动。

 

写一个shell脚本,实现上述功能。彻底杀死一个进程的命令是 kill -9 pid.

答 : 注明:以下脚本为猿课同学实际线上跑的shell脚本,考虑的方面比较多,大家可以学一学他的思路

 

#!/bin/bash

###功能: 重启 tomcat 进程

###要求:对于tomcat中的某些应用,使用shutdown.sh是无法完全停掉所有服务的 实际操作中都需要kill掉tomcat再重启

##

### root can not run this script.

##

if [ $USER = root ]

then

        echo "root cann't run this script!please run with other user!"

        exit 1

fi

##

### check the Parameter

##

if [[ $# -ne 1 ]]

then

        echo "Usage:$0 tomcatname"

        exit 1

fi

##

### only one process can run one time

##

TMP_FILE_U=/tmp/.tmp.ps.keyword.$USER.956327.txt

#echo $TMP_FILE_U

KEYWORD1="$0"

KEYWORD2="$1"

# 使用赋值会多fork出一个进程,所以要先重定向到一个文本,再统计.

ps ux |grep "$KEYWORD1"|grep "\<$KEYWORD2\>"|grep -v "grep" > $TMP_FILE_U

Pro_count=`cat $TMP_FILE_U |wc -l`

if [ $Pro_count -gt 1 ]

then

        echo "An other process already running ,exit now!"

        exit 1

fi

###################################################

#                                                 #

#               begin of the script               #

#                                                 #

###################################################

##

### set the Parameter

##

TOM=`echo $1|sed 's#/##g'`

TOMCAT_DIRECTORY=~/usr/local/$TOM

STARTUP_SCRIPT=$TOMCAT_DIRECTORY/bin/startup.sh

TOMCAT_LOG=$TOMCAT_DIRECTORY/logs/catalina.out

CONF_FILE=$TOMCAT_DIRECTORY/conf/server.xml

TEMPFILE=/tmp/.tmpfile.x.89342.c4r3.tmp

##

### check if the tomcat directory exist

##

if [ ! -d "$TOMCAT_DIRECTORY" ]

then

        echo "the tomcat \"$TOM\" not exist.check again!"

        exit 1

fi

##

### log roteta and delete log one week ago

##

rotate_log(){

TIME_FORMART=$(date +%Y%m%d%H%M%S)

LOG_DIR=$(dirname $TOMCAT_LOG)

mv $TOMCAT_LOG ${TOMCAT_LOG}_${TIME_FORMART}

find $LOG_DIR -type f -ctime +7 -exec rm -rf {} \;

}

##

### function start the tomcat

##

start_tomcat()

{

#echo start-tomcat-func

if [ -x  "$STARTUP_SCRIPT" ]

then

        

        rotate_log

        $STARTUP_SCRIPT

        sleep 1

        tail -f $TOMCAT_LOG

else

        if [ -e $STARTUP_SCRIPT ]

        then

                chmod +x $STARTUP_SCRIPT

#               echo "permition added!"

                if [ -x  "$STARTUP_SCRIPT" ]

                then

                        

                        rotate_log

                        $STARTUP_SCRIPT

                        sleep 1

                        tail -f $TOMCAT_LOG

                else

                        echo "The script not have excute permision,Couldn't add permision to Script!"

                        exit 1

                fi

        else

                echo "error,the script \"startup.sh\" not exist!"

                exit 1

        fi

fi

}

##

### function stop the tomcat

##

stop_tomcat()

{

rm -rf $TEMPFILE

ps ux |grep /$TOM/ |grep -v "grep /$TOM/"|grep java > $TEMPFILE

Pro_Count=`cat $TEMPFILE|wc -l`

PIDS=`cat $TEMPFILE|awk '{print $2}'`

rm -rf $TEMPFILE

#echo $Pro_Count

if [ $Pro_Count -eq 0 ]

then

        echo "The tomcat not running now!"

else

        if [ $Pro_Count -ne 1 ]

        then

                echo "The have $Pro_Count process running,killed!"

                kill -9 `echo $PIDS`

                WC=`ps aux | grep "/$TOM/" | grep -v "grep /$TOM/" | grep java |wc -l`

                [ $WC -ne 0 ] && (echo "kill process failed!";exit 1)

        else

                echo "Process killed!"

                kill -9 `echo $PIDS`

                WC=`ps aux | grep "/$TOM/" | grep -v "grep /$TOM/" | grep java |wc -l`

                [ $WC -ne 0 ] && (echo "kill process failed!";exit 1)

        fi

fi

}

###########################

####                   ####

####  The main script  ####

####                   ####

###########################

echo -e "are you sure restart $TOM?(y or n)"

read ANS

if [ "$ANS"a != ya ]

then

   echo -e "bye! \n"

   exit 1

fi

stop_tomcat

echo "start tomcat ..."

sleep 2

start_tomcat

# end

 

68、在centos6系统里,我们可以使用ntsysv关闭不需要开机启动的服务,当然也可以使用chkconfig工具来实现。

 

写一个shell脚本,用chkconfig工具把不常用的服务关闭。脚本需要写成交互式的,需要我们给它提供关闭的服务名字。

#!/bin/bash

LANG=en

c="1"

while [ ! $c == "q" ]

do

    echo -e "\033[35mPlease chose a service to close from this list: \033[0m"

    chkconfig --list |awk '/3:on/ {print $1}'

    read -p "Which service to close: " s

    chkconfig $s off

    service $s stop

    read -p  "If you want's to quit this program, tab "q", or tab "Ctrl c": " c

done

 

69、统计并发量

需求背景:

需要统计网站的并发量,并绘图。

 

思路: 

1 借助zabbix成图

2 通过统计访问日志每秒的日志条数来判定并发量

3 zabbix获取数据间隔30s

说明: 只需要写出shell脚本即可,不用关心zabbix配置。

假设日志路径 /data/logs/www.aaa.com_access.log 

日志格式如下

112.107.15.12 - [07/Nov/2017:09:59:01 +0800] www.aaa.com "/api/live.php" 200"-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)"

 

答 #!/bin/bash

log=/data/logs/www.aaa.com_access.log

t=`date -d "-1 second" +%Y:%H:%M:%S`

#可以大概分析一下每分钟日志的量级,比如说不超过3000

n=tail -3000 $log |grep -c "$t"

echo $n

 

70、需求背景是:

一个业务,有3台服务器(A,B,C)做负载均衡,由于规模太小目前并未使用专业的自动化运维工具。有新的需求时,开发同事改完代码会把变更上传到其中一台服务器A上。但是其他2台服务器也需要做相同变更。

写一个shell脚本,把A服务器上的变更代码同步到B和C上。

 

其中,你需要考虑到不需要同步的目录(假如有tmp、upload、logs、caches)

答 : 

#!/bin/bash

echo "该脚本将会把A机器上的/data/wwwroot/www.aaa.com目录同步到B,C机器上";

read -p "是否要继续?(y|n) "

rs() {

    rsync -azP \

    --exclude logs \

    --exclude upload \

    --exclude caches \

    --exclude tmp \

www.aaa.com/ $1:/data/wwwroot/www.aaa.com/

}

if [ $REPLY == 'y' -o $REPLY == 'Y' ]

then

    echo "即将同步……"

    sleep 2

    cd /data/wwwroot/

    rs B机器ip

    rs C机器ip

    echo "同步完成。"

    

elif [ $REPLY == 'n' -o $REPLY == 'N' ]

then

    exit 1

else

    echo "请输入字母y或者n"

fi

 

71、写一个脚本让用户输入多个城市的名字(可以是中文),要求不少于5个,然后把这些城市存到一个数组里,最后用for循环把它们打印出来。

#!/bin/bash  

read -p "请输入至少5个城市的名字,用空格分隔:" city

n=`echo $city|awk '{print NF}'`

if [ $n -lt 5 ]

then

    echo "输入的城市个数至少为5"

    exit

fi

name=($city)

for i in ${name[@]}

do

    echo $i

done

 

72、写一个截取tomcat   catalina.out日志的脚本

tomcat实例t1-t4

 

# tree  -L  1   /opt/TOM/

/opt/TOM/

├── crontabs

├── t1

├── t2

├── t3

└── t4

5 directories, 0 files

 

# find  /opt/TOM/   -name  catalina.out

/opt/TOM/t1/logs/catalina.out

/opt/TOM/t3/logs/catalina.out

/opt/TOM/t4/logs/catalina.out

/opt/TOM/t2/logs/catalina.out

 

要求:

1.这个脚本可以取tomcat实例t1-t4的日志

2.这个脚本可以自定义取日志的起始点 ,比如取今天早上10点之后到现在的数据

3.这个脚本可以自定义取日志的起始点和终点,比如取今天早上9点到晚上8点的数据

 

catalina.out 日志内容

 

Mar 29, 2016 1:52:24 PM org.apache.coyote.AbstractProtocol start

INFO: Starting ProtocolHandler ["http-bio-8080"]

Mar 29, 2016 1:52:24 PM org.apache.coyote.AbstractProtocol start

INFO: Starting ProtocolHandler ["ajp-bio-8009"]

Mar 29, 2016 1:52:24 PM org.apache.catalina.startup.Catalina start

INFO: Server startup in 2102 ms

答  :

#!/bin/bash

##

#Author: 7期孙东

#

 

export LANG=en_US.UTF-8

export PATH=$PATH

IPADD=`/sbin/ifconfig | grep "inet addr" | head -1 | awk '{print $2}'| awk -F '.' '{print $NF}'`

LOGFILE="/opt/TOM/$1/logs/catalina.out"

YEAR=`date +%Y`

DATE=`date +%m%d_%H%M`

TOMCAT=$1

BEGIN_TIME=$YEAR$2

END_TIME=$YEAR$3

##judge is  a.m.or p.m.

TIME_HOUR1=`echo ${BEGIN_TIME:9:2}`

cut_log() {

        N_DATE1=`echo $1 | sed 's/_/ /g'`

        D_DATE1=`echo $2 | sed 's/_/ /g'`

        E_DATE1=`echo $3 | sed 's/_/ /g'`

        [ $4 ] && N_DATE2=`echo $4 | sed 's/_/ /g'`

        [ $5 ] && D_DATE2=`echo $5 | sed 's/_/ /g'`

        [ $6 ] && E_DATE2=`echo $6 | sed 's/_/ /g'`

                BEGIN=`grep -nE "${N_DATE1}|${D_DATE1}|${E_DATE1}" ${LOGFILE} | head -1 | cut -d : -f1`

                [ "$N_DATE2" ] && END=`grep -nE "${N_DATE2}|${D_DATE2}|${E_DATE2}" ${LOGFILE} | tail -1 | cut -d : -f1`

                [ ! -z "${TIME_HOUR1}" ] && if [ ${TIME_HOUR1} -gt 12 ] ; then

                BEGIN1=`grep -nE "${N_DATE1}|${D_DATE1}|${E_DATE1}" ${LOGFILE} |grep " PM " |grep "${E_DATE1}" | head -1 | cut -d : -f1`

                if [ ! -z "${BEGIN1}" ] ; then

                [ "${BEGIN1}" -gt "${BEGIN}" ] ; BEGIN=${BEGIN1}

                fi

        fi

        if [ "$BEGIN" ] && [ -z "$END" ] ; then

                if [ "$N_DATE2" ]; then

                        echo  "${END_TIME}时间点没有访问日志,请重新设置时间点."

                else

                        sed -n "${BEGIN},[        DISCUZ_CODE_0        ]quot;p ${LOGFILE} > /home/gcweb/${IPADD}_${TOMCAT}_${DATE}.log

                fi

        elif [ "$END" ];then

                [ "$BEGIN" ] || BEGIN=1

                sed -n "${BEGIN},${END}"p ${LOGFILE} > /home/gcweb/${IPADD}_${TOMCAT}_${DATE}.log

        else

                [ "$END_TIME" != "$YEAR" ] && echo "该时段 ${BEGIN_TIME}~${END_TIME} 没有日志."

                [ "$END_TIME" = "$YEAR" ] && echo "该时段 ${BEGIN_TIME}~now 没有日志."

        fi

        if [ -s /home/gcweb/${IPADD}_${TOMCAT}_${DATE}.log ]; then

                cd /home/gcweb  &&  tar -zcf ${IPADD}_${TOMCAT}_${DATE}.tar.gz ${IPADD}_${TOMCAT}_${DATE}.log

                rm -f /home/gcweb/${IPADD}_${TOMCAT}_${DATE}.log

                sz /home/gcweb/${IPADD}_${TOMCAT}_${DATE}.tar.gz

                echo "Success to get logs."

                rm -f /home/gcweb/${IPADD}_${TOMCAT}_${DATE}.tar.gz

        fi

}

get_time() {

        case "$1" in

                4)      

                 N_DATE=`date -d "$2" +"%Y-%m-%d" 2>/dev/null`

                 D_DATE=`date -d "$2" +"%Y/%m/%d" 2>/dev/null`

                 E_DATE=`date -d "$2" +"%h %e,_%Y" 2>/dev/null|sed 's/ /_/g'`

                 echo $N_DATE $D_DATE $E_DATE

                 ;;      

                7)      

                 TIME=`echo $2 | awk -F'_' '{print $1,$2}'`

                 N_DATE=`date -d "$TIME" +"%Y-%m-%d_%H" 2>/dev/null`

                 D_DATE=`date -d "$TIME" +"%Y/%m/%d_%H" 2>/dev/null`

                 E_DATE=`date -d "$TIME" +"%h %e,_%Y %l" 2>/dev/null|sed 's/ /_/g'`

                 echo  "$N_DATE"  "$D_DATE" "$E_DATE"

                ;;

                9)     

                 TIME=`echo $2 | awk -F'_' '{print $1,$2}'`

                 N_DATE=`date -d "$TIME" +"%Y-%m-%d_%H:%M" 2>/dev/null`

                 D_DATE=`date -d "$TIME" +"%Y/%m/%d_%H:%M" 2>/dev/null`

                 E_DATE=`date -d "$TIME" +"%h %e,_%Y %l:%M" 2>/dev/null|sed 's/ /_/g'`

                 echo  "$N_DATE" "$D_DATE" "$E_DATE"

                ;;

                *)      

                 echo 1

                ;;

       esac

}

check_arguments () {

        if [ "$1" == 1 ] || [ -z  "$1" ] ;then

                echo "你输入时间参数的格式无法识别, usage: 0108、0108_10、0108_1020"

                exit 3

        fi

}

check_tomcat () {

        if [ ! -s "${LOGFILE}" ] ;then

          echo "tomcat_name: ${TOMCAT} is not exist"

          echo "you can choose:"

          /bin/ls  /home/gcweb/usr/local/

        fi

        if [ $1 -lt 2 ] || [ ! -s "${LOGFILE}" ];then

                echo "usage: $0 tomcat_name {begin_time|begin_time end_time}"

                exit 2

        fi

}

case "$#" in

    0)

        echo "usage: $0 tomcat_name {begin_time|begin_time end_time}"

        exit 1

        ;;

    1)

        check_tomcat $#

        ;;

    2)

        check_tomcat $#

        len=`echo $2 | awk '{print length($0)}'`

        A_DATE=$(get_time  $len $BEGIN_TIME)

        eval  $( echo $A_DATE |awk '{print "N_DATE="$1,"D_DATE="$2,"E_DATE="$3}')

        check_arguments "${N_DATE}"

        cut_log "${N_DATE}" "${D_DATE}" "${E_DATE}"

        ;;

    3)

        check_tomcat $#

        len1=`echo $2 | awk '{print length($0)}'`

        len2=`echo $3 | awk '{print length($0)}'`

        A_DATE=$(get_time ${len1}  $BEGIN_TIME)

        eval  $( echo $A_DATE |awk '{print "N_DATE1="$1,"D_DATE1="$2,"E_DATE1="$3}')

        check_arguments "${N_DATE1}"

        A_DATE=$(get_time ${len2}  $END_TIME)

        eval  $( echo $A_DATE |awk '{print "N_DATE="$1,"D_DATE="$2,"E_DATE="$3}')

        check_arguments "${N_DATE}"

        cut_log ${N_DATE1} ${D_DATE1} ${E_DATE1} "${N_DATE}" "${D_DATE}" "${E_DATE}"

        ;;

    *)

        echo "usage: $0 tomcat_name {begin_time|begin_time end_time};你使用的参数太多哦."

        ;;

esac

 

73、阿里云的机器,今天收到客服来的电话,说服务器的磁盘io很重。于是登录到服务器查看,并没有发现问题,所以怀疑是间歇性地。

 

正要考虑写个脚本的时候,幸运的抓到了一个线索,造成磁盘io很高的幕后黑手是mysql。此时去show processlist,但未发现队列。原来只是一瞬间。

 

只好继续来写脚本,思路是,每5s检测一次磁盘io,当发现问题去查询mysql的processlist。

 

帮助:你可以用iostat -x 1  5 来判定磁盘的io,主要看%util

答 :

#!/bin/bash

while :

do

    n=`iostat -x 1 5 |tail -n3|head -n1 |awk '{print $NF}'|cut -d. -f1`

    if [ $n -gt 70 ]

    then

        echo "`date` util% is $n%" >>/tmp/mysql_processlist.log

    mysql -uroot -pxxxxxx -e "show  full processlist" >> /tmp/mysql_processlist.log

    fi

    sleep 5

done

 

74、贷款有两种还款的方式:等额本金法和等额本息法

简单说明一下等额本息法与等额本金法的主要区别:


等额本息法的特点是:每月的还款额相同,在月供中“本金与利息”的分配比例中,前半段时期所还的利息比例大、本金比例小,还款期限过半后逐步转为本金比例大、利息比例小。所支出的总利息比等额本金法多,而且贷款期限越长,利息相差越大。


等额本金法的特点是:每月的还款额不同,它是将贷款额按还款的总月数均分(等额本金),再加上上期剩余本金的月利息,形成一个月还款额,所以等额本金法第一个月的还款额最多 ,尔后逐月减少,越还越少。所支出的总利息比等额本息法少。


两种还款方式的比较不是我们今天的讨论范围,我们的任务就是做一个贷款计算器。

其中:等额本息每月还款额的计算公式是:
[贷款本金×月利率×(1+月利率)^还款月数]÷[(1+月利率)^还款月数-1]

答 : 

#!/bin/bash

# Author: Maria.(12期-马黎阳)

# Date & Time: 2016-03-07 09:04:01

# Description: 贷款计算器.

 

read -p "请输入贷款总额(单位:万元):" dkzewy

read -p "请输入贷款年利率(如年利率为6.5%,直接输入6.5):" dknll

read -p "请输入贷款年限(单位:年):" dknx

echo "贷款计算方式:"

echo "1)等额本金计算法"

echo "2)等额本息计算法"

read -p "请选择贷款方式(1|2)" dkfs

dkze=`echo "scale=2;$dkzewy*10000 " | bc -l`

dkll=`echo "scale=6;$dknll/100 " | bc -l`

dkyll=`echo "scale=6;$dkll/12 " | bc -l`

dkqc=$[$dknx*12]

 

echo "期次 本月还款额 本月利息 未还款额"

debjjsf()

{

    yhbj=`echo "scale=2;($dkze/$dkqc)/1 " | bc -l`

    whbj=$dkze

    for((i=1;i<=$dkqc;i++))

    do

        bylx=`echo "scale=2;($whbj*$dkyll)/1 " | bc -l`

        bybx=`echo "scale=2;($yhbj+$bylx)/1 " | bc -l`

        yhke=`echo "scale=2;($yhbj*$i)/1 " | bc -l`

        whbj=`echo "$dkze-$yhke " | bc -l`

        if [ $i -eq $dkqc ]

        then

            yhbj=`echo "scale=2;($yhbj+$whbj)/1 " | bc -l`

            whbj="0.00"

            bybx=`echo "scale=2;($yhbj+$bylx)/1 " | bc -l`

        fi

        echo "$i $bybx $bylx $whbj"

    done

}

 

debxjsf()

{

    bybx=`echo "scale=2;(($dkze*$dkyll*((1+$dkyll)^$dkqc))/(((1+$dkyll)^$dkqc)-1))/1 " | bc -l`

    whbj=$dkze

    for((i=1;i<=$dkqc;i++))

    do

        bylx=`echo "scale=2;($whbj*$dkyll)/1 " | bc -l`

        yhbj=`echo "scale=2;($bybx-$bylx)/1 " | bc -l`

        whbj=`echo "scale=2;($whbj-$yhbj)/1 " | bc -l`

        if [ $i -eq $dkqc ]

        then

            bybx=`echo "scale=2;($yhbj+$whbj)/1 " | bc -l`

            whbj="0.00"

        fi

        echo "$i $bybx $bylx $whbj"

    done

}

 

case $dkfs in

    1) debjjsf

       ;;

    2) debxjsf

       ;;

    *) exit 1

       ;;

esac

 

75、要求:两类机器一共300多台,写个脚本自动清理这两类机器里面的日志文件。在堡垒机批量发布,也要批量发布到crontab里面。


A类机器日志存放路径很统一,B类机器日志存放路径需要用*匹配(因为这个目录里除了日志外,还有其他文件,不能删除。匹配的时候可用*.log)


A类:/opt/cloud/log/   删除7天前的 
B类: /opt/cloud/instances/  删除15天前的 


要求写在一个脚本里面。不用考虑堡垒机上的操作,只需要写出shell脚本。

#!/bin/bash

dir1=/opt/cloud/instances/ 

dir2=/opt/cloud/log/

  if [ -d $dir1 ];then

      find $dir1 -type f -name "*.log" -mtime +15 |xargs rm -f

  elif [ -d $dir2 ];then

      find $dir2 -type f -mtime +7 |xargs rm -f

fi

 

76、有如下文本,其中前5行内容为

1111111:13443253456
2222222:13211222122
1111111:13643543544
3333333:12341243123
2222222:12123123123

 

用shell脚本处理后,按下面格式输出:

[1111111]
13443253456
13643543544
[2222222]
13211222122
12123123123
[3333333]
12341243123

#! /bin/bash

sort -n filename |awk -F ':' '{print $1}'|uniq >id.txt

for id in `cat id.txt`; do

        echo "[$id]"

        awk -v id2=$id -F ':' '$1==id2 {print $2}' filename  // 另外的方式为: awk -F ':' '$1=="'id'" {print $2}' filename  

done

 

77、写一个脚本查找/data/log目录下,最后创建时间是3天前,后缀是*.log的文件,打包后发送至192.168.1.2服务上的/data/log下,并删除原始.log文件,仅保留打包后的文件

#!/bin/bash

find /data/log -name “*.log” -mtime +3 > /tmp/file.list

cd /data/log

tar czvf log.tar.gz `cat /tmp/file.list|xargs`

rsync -a log.tar.gz  192.168.1.2:/data/log  //这一步需要提前做一个免密码登录

for f in `cat /tmp/file.list`

do

    rm -f $f

done

 

78、请使用条件函数if撰写一个shell函数 函数名为 f_judge,实现以下功能

1)当/home/log 目录存在时 将/home目录下所有tmp开头的文件或目录移/home/log 目录。  

 

2)当/home/log目录不存在时,创建该目录,然后退出。

#!/bin/bash

f_judge (){

    if [ -d /home/log ]

    then 

        mv /home/tmp* /home/log/

    else

        mkdir -p /home/log

        exit

    fi

}

 

79、linux系统中,根目录/root/下有一个文件ip-pwd.ini,内容如下

10.111.11.1,root,xyxyxy

10.111.11.1,root,xzxzxz

10.111.11.1,root,123456

10.111.11.1,root,xxxxxx

……

文件中每一行的格式都为linux服务器的ip,root用户名,root密码,请用一个shell批量将这些服务器中的所有tomcat进程kill掉。

 

讲解: 有了ip,用户名和密码,剩下的就是登录机器,然后执行命令了。批量登录机器,并执行命令,咱们课程当中有讲过一个expect脚本。所以本题就是需要这个东西来完成。

首先编辑expect脚本 kill_tomcat.expect

#!/usr/bin/expect

set passwd [lindex $argv 0]

set host [lindex $argv 1]

spawn ssh root@$host

expect {

    "yes/no" { send "yes\r"; exp_continue}

    "password:" { send "$passwd\r" }

}

expect "]*"

send "killall java\r"

expect "]*"

send "exit\r"

 

编辑完后需要给这个文件执行权限 

chmod a+x kill_tomcat.expect

然后编辑shell脚本

#!/bin/bash

n=`wc -l ip-pwd.ini`

for i in `seq 1 $n`

do

    ip=`sed -n "$n"p ip-pwd.ini |awk -F ',' '{print $1}'`

    pw=`sed -n "$n"p ip-pwd.ini |awk -F ',' '{print $3}'`

    ./kill_tomcat.expect $pw $ip

done

 

80、linux系统 /home目录下有一个文件test.xml,内容如下:

 

   

       

       zzz

       aaa

   

   

       xxx

       yyy

   

   

   

 

请写出shell脚本删除文件中的注释部分内容,获取文件中所有artifactItem的内容,并用如下格式逐行输出 artifactItem:groupId:artifactId

 

分析:这个文件比较特殊,但是却很有规律。注释部分内容其实就是中间的内容,所以我们想办法把这些内容删除掉就ok了。而artifactItem的内容,其实就是获取中间的内容。然后想办法用提到的格式输出即可。

答 :

#!/bin/bash

egrep -v '' 1.txt |tee 2.txt  //这行就是删除掉注释的行

grep -n 'artifactItem>' 2.txt |awk '{print $1}' |sed 's/://' > /tmp/line_number.txt

n=`wc -l /tmp/line_number.txt|awk '{print $1}'`

 

get_value(){

    sed -n "$1,$2"p 2.txt|awk -F '<' '{print $2}'|awk -F '>' '{print $1,$2}' > /tmp/value.txt

    nu=`wc -l /tmp/value.txt|awk '{print $1}'`

    for i in `seq 1 $nu`

    do

        x=`sed -n "$i"p /tmp/value.txt|awk '{print $1}'`

        y=`sed -n "$i"p /tmp/value.txt|awk '{print $2}'`

        echo artifactItem:$x:$y

    done

}

 

n2=$[$n/2]

 

for j in `seq 1 $n2`

do

    m1=$[$j*2-1]

    m2=$[$j*2]

    nu1=`sed -n "$m1"p /tmp/line_number.txt`

    nu2=`sed -n "$m2"p /tmp/line_number.txt`

    nu3=$[$nu1+1]

    nu4=$[$nu2-1]

    get_value $nu3 $nu4

done

 

81、写一个脚本,依次向/etc/passwd中的每个用户问好,并且说出对方的ID是什么
Hello,root,your UID is 0.

awk -F ':' '{print "Hello,"$1",your uid is "$3.}' /etc/passwd 

 

82、交互式脚本,根据提示,需要用户输入一个数字作为参数,最终打印出一个正方形。

在这里我提供一个linux下面的特殊字符■,可以直接打印出来。

 

示例: 如果用户输入数字为5,则最终显示的效果为

■ ■ ■ ■ ■

■ ■ ■ ■ ■

■ ■ ■ ■ ■

■ ■ ■ ■ ■

■ ■ ■ ■ ■

#!/bin/bash

read -p "please input a number:" sum

a=`echo $sum |sed 's/[0-9]//g'`

if [ -n "$a" ]

then

    echo "请输入一个纯数字。"

    exit 1

fi

for n in `seq $sum`

do

    for m in `seq $sum`

    do

        if [ $m -lt $sum ]

        then

            echo -n "■ "

        else

            echo "■"

        fi

    done

done

 

83、用户交互脚本

写一个脚本,执行后,打印一行提示“Please input a number:",要求用户输入数值,然后打印出该数值,然后再次要求用户输入数值。直到用户输入"end"停止。

#!/bin/bash

while :

do

        read -p "Please input a number:(end for exit) " n

        num=` echo $n |sed -r 's/[0-9]//g'|wc -c `

        if [ $n == "end" ]

                then

                        exit

                elif [ $num -ne 1  ]

                        then

                        echo "what you input is not a number!Try again!"

                else

                        echo "your input number is: $n"

        fi

done

 

84、判断所给目录内哪些二级目录下没有text.txt文件。

有text.txt文件的二级目录,根据文件计算选项中单词数最大的值(选项间以|分割,单词间以空格分隔)。

假如脚本名字为1.sh, 运行脚本的格式为 ./1.sh  123  root,其中123为目录名字,而root为要计算数量的单词。

答 :说明: 这个shell脚本题目出的有点歧义。 原题给的描述不是很清楚,我另外又改了一下需求,依然不是很清晰。在这里我再做一个补充: 对于有test.txt的目录,计算出该test.txt文件里面所给出单词的次数。不用找最大。

 

#!/bin/bash

if [ $# -ne 2 ]

then

    echo "useage $0 dir word"

    exit 1

fi

if [ -d $1 ]

then

    cd $1

else

    echo "$1目录不存在"

    exit 1

fi

for f in `ls $1`

do

    if [ -d $f ]

    then

    if [ -f $f/test.txt ]

    then

        n=`grep -cw "$2" $f/test.txt`

        echo "$1/$f/test.txt 里面有$n个$2"

    else

        echo "$1/$f 下面没有test.txt"

        fi

    fi

done

 

85、用shell写一个简易计算器,可以实现加、减、乘、除运算,假如脚本名字为1.sh,执行示例:./1.sh 1 + 2 

#!/bin/bash

if [ $# -ne 3 ] 

then

    echo "参数个数不为3"

    echo "当使用乘法时,需要加上脱义符号,例如 $0 1 \* 2"

    exit 1;

fi

num1=`echo $1|sed 's/[0-9.]//g'` ;

if [ -n "$num1" ] 

then

    echo "$1 不是数字" ;

    exit 1

fi

 

num3=`echo $3|sed 's/[0-9.]//g'` ;

if [ -n "$num3" ]

then

    echo "$3 不是数字" ;

    exit 1

fi

 

case $2 in

  +)

    echo "scale=2;$1+$3" | bc

    ;;

 

  -)

    echo "scale=2;$1-$3" | bc 

    ;;

  

  \*)

    echo "scale=2;$1*$3" | bc 

    ;;

  

  /)

    echo "scale=2;$1/$3" | bc 

    ;;

  

  *)

   echo  "$2 不是运算符"

   ;;

esac

 

86、需求背景:  
服务器上,跑的lamp环境,上面有很多客户的项目,每个项目就是一个网站。 由于客户在不断增加,每次增加一个客户,就需要配置相应的mysql、ftp以及httpd. 这种工作是重复性非常强的,所以用脚本实现非常合适。

 

mysql增加的是对应客户项目的数据库、用户、密码,ftp增加的是对应项目的用户、密码(使用vsftpd,虚拟用户模式),httpd就是要增加虚拟主机配置段。

#!/bin/bash

webdir=/home/wwwroot

ftpudir=/etc/vsftpd/vuuser

mysqlc="/usr/bin/mysql -uroot -xxxxxx"

httpd_config_f="/usr/local/apache2/conf/extra/httpd-vhosts.conf"

 

add_mysql_user()

{

        mysql_p=`mkpasswd -s 0 -l 12`

        echo "$pro $mysql_p" >/tmp/$pro.txt

        $mysqlc <

        grant all on $p.* to "$pro"@'127.0.0.1' identified by "$mysql_p";

EOF

 

}

 

add_ftp_user()

{

        ftp_p=`mkpasswd -s 0 -l 12`

        echo "$pro" >> /root/login.txt

        echo "$ftp_p" >> /root/login.txt

        db_load -T -t hash -f /root/login.txt  /etc/vsftpd/vsftpd_login.db

        cd $ftpudir

        cp aaa $pro   //这里的aaa是一个文件,是之前的一个项目,可以作为配置模板

        sed -i "s/aaa/$pro/" $pro  //把里面的aaa改为新的项目名字

        /etc/init.d/vsftpd restart

}

 

config_httpd()

{

        mkdir $webdir/$pro

        chown vsftpd:vsftpd $webdir/$pro

        echo -e " \n     DocumentRoot "/home/internet/www/$pro/" \n     ServerName $dom \n    #ServerAlias \n " >> $httpd_config_f

        /usr/local/apache2/bin/apachectl graceful

}

 

read -p "input the project name: " pro

read -p "input the domain: " dom

 

add_mysql_user

add_ftp_user

config_httpd

 

87、 获取子进程

说明:本shell题目是一个网友在公众号中提问的,正好利用这个每日习题的机会拿出来让大家一起做一做。

 

给出一个进程PID,打印出该进程下面的子进程以及子进程下面的所有子进程。(只需要考虑子进程的子进程,再往深层次则不考虑)

#!/bin/bash

read -p "please input a pid number: " p

ps -elf > /tmp/ps.log

 

is_ppid(){

    awk '{print $5}' /tmp/ps.log > /tmp/ps1.log

    if ! grep -qw "$1" /tmp/ps1.log

    then

        echo "PID $1 不是系统进程号,或者它不是父进程"

    return 1

    fi

}

 

is_ppid $p

if [ $? -eq "1" ]

then

    exit

fi

 

print_cpid(){

    p=$1

    awk -v p1=$p '$5 == p1 {print $4}' /tmp/ps.log |sort -n |uniq >/tmp/p1.log

    n=`wc -l /tmp/p1.log|awk '{print $1}'`

    if [ $n -ne 0 ]

    then

        echo "PID $p 子进程 pid 如下:"

        cat /tmp/p1.log

    else

    echo "PID $p 没有子进程"

    fi

}

 

print_cpid $p

for cp in `cat /tmp/p1.log`

do

    print_cpid $cp

done

 

另外,一条命令查询的方法是:pstree -p pid

 

88、用shell打印下面这句话中字母数小于6的单词。
Bash also interprets a number of multi-character options.

#!/bin/bash

for s in Bash also interprets a number of multi-character options

do 

    n=`echo $s|wc -c`

    if [ $n -lt 6 ]

        then echo $s

    fi

done

 

89、输入数字执行对应命令

写一个脚本实现如下功能:  输入一个数字,然后运行对应的一个命令。显示命令如下:*cmd meau**  1---date 2--ls 3--who 4--pwd
当输入1时,会运行date, 输入2时运行ls, 依此类推。

 

90、要求:

把一个文本文档的前5行中包含字母的行删除掉,同时把6到10行中的全部字母删除掉。

 

答 :假设文本名字叫做1.txt,并且文本行数大于10,脚本如下

 

#!/bin/bash

##先获取该文本的行数

nu=`wc -l 1.txt |awk '{print $1}'`

##对前5行进程处理

for i in `seq 1 5`

do 

    ##使用sed把每一行的内容赋值给变量

    l=`sed -n "$i"p 1.txt`

    ##用grep 判定是否匹配字母,-v取反,-q不输出内容

    if echo $l |grep -vq '[a-zA-Z]'

    then

echo $l

    fi

done

##对6-10行做删除字母处理

for i in `seq 6 10`

do

    l=`sed -n "$i"p 1.txt`

    echo $l|sed 's/[a-zA-Z]//g'

done

##剩余的直接输出

for i in `seq 11 $nu`

do

    sed -n "$i"p 1.txt

done

##若想把更改内容写入到1.txt,还需要把以上内容重定向到一个文本中,然后删除1.txt,再把刚刚重定向的文件更名为1.txt

 

91、自动重启nginx服务

服务器上跑的是LNMP环境,近期总是有502现象。502为网站访问的状态码,200正常,502错误是nginx最为普通的错误状态码。由于502只是暂时的,并且只要一重启php-fpm服务则502消失,但不重启的话,则会一直持续很长时间。所以有必要写一个监控脚本,监控访问日志的状态码,一旦发生502,则自动重启一下php-fpm。

我们设定: 
1. access_log  /data/log/access.log
2. 脚本死循环,每10s检测一次(假设每10s钟的日志条数为300左右)
3. 重启php-fpm的方法是  /etc/init.d/php-fpm restart

 

答 : 其实不是重启nginx,应该说是自动重启php-fpm服务。

 

#! /bin/bash

log=/data/log/access.log

N=10

while :; do

    ##因为10秒钟大概产生300条日志

    tail -n 300 $log > /tmp/log

    n_502=`grep -c ' 502"' /tmp/log`

    if [ $n_502 -ge $N ]; then

        ##记录系统的状态

        top -bn1 >/tmp/`date +%H%M%S`-top.log

        vmstat 1 5 >/tmp/`date +%H%M%S`-vm.log

        /etc/init.d/php-fpm restart 2>/dev/null

        ##重启php-fpm服务后,应先暂缓1分钟,而后继续每隔10s检测一次

        sleep 60

    fi    

    sleep 10

done

 

92、备份数据库【答案】

#! /bin/bash

### backup mysql data

### Writen by Aming.

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/mysql/bin

d1=`data +%w`

d2=`date +%d`

pass="your_mysql_password"

bakdir=/bak/mysql

r_bakdir=192.168.123.30::backup

 

exec 1>/var/log/mysqlbak.log 2>/var/log/mysqlbak.log

 

echo "mysql backup begin at `date +"%F %T"`."

mysqldump -uroot -p$pass --default-character-set=gbk discuz >$bakdir/$d1.sql

rsync -az $bakdir/$d1.sql $r_bakdir/$d2.sql

echo "mysql backup end at `date +"%F %T"`."

然后加入cron

0 3 * * * /bin/bash /usr/local/sbin/mysqlbak.sh

 

93、使用传参的方法写个脚本,实现加减乘除的功能。例如:  sh  a.sh  1   2,这样会分别计算加、减、乘、除的结果。

要求:

1 脚本需判断提供的两个数字必须为整数

2 当做减法或者除法时,需要判断哪个数字大

3 减法时需要用大的数字减小的数字

4 除法时需要用大的数字除以小的数字,并且结果需要保留两个小数点。

#!/bin/bash

if [ $# -ne 2 ]

then

    echo "The number of parameter is not 2, Please useage: ./$0 1 2"

    exit 1

fi

 

is_int()

{

    if echo "$1"|grep -q '[^0-9]'

    then

    echo "$1 is not integer number."

    exit 1

    fi

}

 

max()

{

    if [ $1 -ge $2 ]

    then

    echo $1

    else

    echo $2

    fi

}

 

min()

{

    if [ $1 -lt $2 ]

    then

    echo $1

    else

    echo $2

    fi

}

 

sum()

{

    echo "$1 + $2 = $[$1+$2]"

}

 

minus()

{

    big=`max $1 $2`

    small=`min $1 $2`

    echo "$big - $small = $[$big-$small]"

}

 

mult()

{

    echo "$1 * $2 = $[$1*$2]"

}

 

div()

{

    big=`max $1 $2`

    small=`min $1 $2`

    d=`echo "scale =2; $big / $small"|bc`

    echo "$big / $small = $d"

}

 

is_int $1

is_int $2

sum $1 $2

minus $1 $2

mult $1 $2

div $1 $2

 

94、写一个脚本: 计算100以内所有能被3整除的正整数的和

#!/bin/bash
sum=0
for i in {1..100};do
    if [ $[$i%3] -eq 0 ];then
    sum=$[$i+$sum]
     fi
done

echo "sum:$sum"

 

95、带选项的用户脚本

要求如下:

 

  • 只支持三个选项 ‘--del’ ‘--add’ --help输入其他选项报错。

  • 使用‘--add’需要验证用户名是否存在,存在则反馈存在。且不添加。 不存在则创建该用户,切添加与该用户名相同的密码。并且反馈。

  • 使用‘--del’ 需要验证用户名是否存在,存在则删除用户及其家目录。不存在则反馈该用户不存在。

  • --help 选项反馈出使用方法

  • 支持以,分隔   一次删除多个或者添加多个用户。

  • 能用echo $?  检测脚本执行情况  成功删除或者添加为0,报错信息为其他数字。

  • 能以,分割。一次性添加或者 删除多个用户。  例如 adddel.sh --add user1,user2,user3.......

  • 不允许存在明显bug。

#!/bin/bash

#written by aming.

if [ $# -eq 0 -o $# -gt 2 ]

then

    echo "use $0 --add username or $0 --del username or $0 --help."

    exit 1

fi

case $1 in

    --add)

        n=0

        for u in `echo $2|sed 's/,/ /g'`; do

            if awk -F: '{print $1}' /etc/passwd |grep -qw "$u"

            then

                echo "The user $u exist."

            else

                useradd $u

                echo -e "$u\n$u"|passwd $u >/dev/null 2>&1

                echo "The user $u added successfully."

                n=$[$n+1]

            fi

        done

        if [ $n -eq 0 ]; then

            exit 2

        fi

        ;;

    --del)

        n=0

        for u in `echo $2|sed 's/,/ /g'`; do

            if awk -F: '{print $1}' /etc/passwd|grep -qw "$u"

            then

                userdel -r $u

                echo "The user $u deleted successfully."

                n=$[$n+1]

            else

                echo "The user $u not exist."

            fi

        done

        if [ $n -eq 0 ]; then

                exit 3

        fi

        ;;

    --help)

        echo -e "--add can add user,and the passwd is the same as username.     

    It can add multiuser such as --add user1,user2,user3..."

        echo "--del cat delete user.It can delete user such as --del user1,user2,user3..."

        ;;

    *)

        echo "use $0 --add username or $0 --del username or $0 --help."

        exit 1

        ;;

esac

 

96、假设,当前MySQL服务的root密码为123456,写脚本检测MySQL服务是否正常(比如,可以正常进入mysql执行show processlist),并检测一下当前的MySQL服务是主还是从,如果是从,请判断它的主从服务是否异常。如果是主,则不需要做什么。

#!/bin/bash

Mysql_c="mysql -uroot -p123456"

$Mysql_c -e "show processlist" >/tmp/mysql_pro.log 2>/tmp/mysql_log.err

n=`wc -l /tmp/mysql_log.err|awk '{print $1}'`

if [ $n -gt 0 ]

then

    echo "mysql service sth wrong."

else

    $Mysql_c -e "show slave status\G" >/tmp/mysql_s.log

    n1=`wc -l /tmp/mysql_s.log|awk '{print $1}'`

    if [ $n1 -gt 0 ]

    then

        y1=`grep 'Slave_IO_Running:' /tmp/mysql_s.log|awk -F : '{print $2}'|sed 's/ //g'`

        y2=`grep 'Slave_SQL_Running:' /tmp/mysql_s.log|awk -F : '{print $2}'|sed 's/ //g'`

        if [ $y1 == "Yes" ] && [ $y2 == "Yes" ]

        then

            echo "slave status good."

        else

            echo "slave down."

        fi

    fi

fi

 

97、写一个脚本判断你的Linux服务器里是否开启web服务?(监听80端口)如果开启了,请判断出跑的是什么服务,是httpd呢还是nginx又或者是其他的什么?

#!/bin/bash

port=`netstat -lnp | grep 80`

if [ -z "port" ]; then

    echo "not start service.";

    exit;

fi

web_server=`echo $port | awk -F'/' '{print $2}'|awk -F : '{print $1}'`

case $web_server in

    httpd )     

        echo "apache server." 

    ;;     

    nginx )     

         echo "nginx server." 

    ;;   

    * ) 

         echo "other server."   

    ;;   

esac 

 

98、监控磁盘使用率

写一个shell脚本,检测所有磁盘分区使用率和inode使用率并记录到以当天日期为命名的日志文件里,当发现某个分区容量或者inode使用量大于85%时,发邮件通知你自己。

思路:就是先df -h 然后过滤出已使用的那一列,然后再想办法过滤出百分比的整数部分,然后和85去比较,同理,inode也是一样的思路。

#!/bin/bash
## This script is for record Filesystem Use%,IUse% everyday and send alert mail when % is more than 85%.

log=/var/log/disk/`date +%F`.log
date +'%F %T' > $log
df -h >> $log
echo >> $log
df -i >> $log

for i in `df -h|grep -v 'Use%'|sed 's/%//'|awk '{print $5}'`; do
    if [ $i -gt 85 ]; then
        use=`df -h|grep -v 'Use%'|sed 's/%//'|awk '$5=='$i' {print $1,$5}'`
        echo "$use" >> use
    fi
done
if [ -e use ]; then

   ##这里可以使用咱们之前介绍的mail.py发邮件
    mail -s "Filesystem Use% check" root@localhost < use
    rm -rf use
fi

for j in `df -i|grep -v 'IUse%'|sed 's/%//'|awk '{print $5}'`; do
    if [ $j -gt 85 ]; then
        iuse=`df -i|grep -v 'IUse%'|sed 's/%//'|awk '$5=='$j' {print $1,$5}'`
        echo "$iuse" >> iuse
    fi
done
if [ -e iuse ]; then
    mail -s "Filesystem IUse% check" root@localhost < iuse
    rm -rf iuse
fi

思路:
1、df -h、df -i 记录磁盘分区使用率和inode使用率,date +%F 日志名格式
2、取出使用率(第5列)百分比序列,for循环逐一与85比较,大于85则记录到新文件里,当for循环结束后,汇总超过85的一并发送邮件(邮箱服务因未搭建,发送本地root账户)。

此脚本正确运行前提:

该系统没有逻辑卷的情况下使用,因为逻辑卷df -h、df -i 时,使用率百分比是在第4列,而不是第5列。如有逻辑卷,则会漏统计逻辑卷使用情况。

 

99、写个shell,看看你的Linux系统中是否有自定义用户(普通用户),若是有,一共有几个?

假设所有普通用户都是uid大于1000的

#!/bin/bash
n=`awk -F ':' '$3>1000' /etc/passwd|wc -l`
if [ $n -gt 0 ]
then
    echo "There are $n common users."
else
    echo "No common users."
fi

 

100、请详细查看如下几个数字的规律,并使用shell脚本输出后面的十个数字。
10 31 53 77  105 141 .......

试题解析:
我想大多数人都会去比较这些数字的差值:
10  31  53  77  105  141
   21   22   24   28   36
但是这个差值看,并没有什么规律,而我们再仔细看的时候,发现这个差值的差值是有规律的:
10  31  53  77  105  141
   21   22   24   28   36
       1      2     4     8

#! /bin/bash

x=21

m=10

echo $m

for i in `seq 0 14`; do

    j=$[2**$i]

    m=$[$m+$x]

    echo $m

    x=$[$x+$j]

done

 

101、需求: 根据web服务器上的访问日志,把一些请求量非常高的ip给拒绝掉! 
分析: 我们要做的,不仅是要找到哪些ip请求量不合法,并且还要每隔一段时间把之前封掉的ip(若不再继续请求了)给解封。 所以该脚本的关键点在于定一个合适的时间段和阈值。 

比如, 我们可以每一分钟去查看一下日志,把上一分钟的日志给过滤出来分析,并且只要请求的ip数量超过100次那么就直接封掉。 而解封的时间又规定为每半小时分析一次,把几乎没有请求量的ip给解封!


参考日志文件片段:

157.55.39.107 [20/Mar/2015:00:01:24 +0800] www.aminglinux.com "/bbs/thread-5622-3-1.html" 200 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)" 
61.240.150.37 [20/Mar/2015:00:01:34 +0800] www.aminglinux.com "/bbs/search.php?mod=forum&srchtxt=LNMP&formhash=8f0c7da9&searchsubmit=true&source=hotsearch" 200 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"

#! /bin/bash

logfile=/home/logs/access.log
d1=`date -d "-1 minute" +%H:%M`
d2=`date +%M`
ipt=/sbin/iptables
ips=/tmp/ips.txt

block(){
    grep "$d1:" $logfile|awk '{print $1}' |sort -n |uniq -c |sort -n >$ips
    for ip in `awk '$1>100 {print $2}' $ips`; do
        $ipt -I INPUT -p tcp --dport 80 -s $ip -j REJECT
        echo "`date +%F-%T` $ip" >> /tmp/badip.txt
    done
}

unblock(){
    for i in `$ipt -nvL --line-numbers |grep '0.0.0.0/0'|awk '$2<15 {print $1}'|sort -nr`; do
        $ipt -D INPUT $i
    done
    $ipt -Z
}

if [ $d2 == "00" ] || [ $d2 == "30" ]; then
    unblock
    block
else
    block
fi

 

102、监控httpd进程

在服务器上,写一个监控脚本。

1. 每隔10s去检测一次服务器上的httpd进程数,如果大于等于500的时候,就需要自动重启一下apache服务,并检测启动是否成功?
2. 若没有正常启动还需再一次启动,最大不成功数超过5次则需要理解发邮件通知管理员,并且以后不需要再检测! 
3. 如果启动成功后,1分钟后再次检测httpd进程数,若正常则重复之前操作(每隔10s检测一次),若还是大于等于500,那放弃重启并需要发邮件给管理员,然后自动退出该脚本。假设其中发邮件脚本为之前咱们使用的mail.py

#!/bin/bash
check_service()
{
    n=0
    for i in `seq 1 5`
    do
        /usr/local/apache2/bin/apachectl restart 2>/tmp/apache.err
        if [ $? -ne 0 ]
        then
            n=$[$n+1]
        else
            break
        fi
    done
    if [ $n -eq 5 ]
    then
        ##下面的mail.py参考https://coding.net/u/aminglinux/p/aminglinux-book/git/blob/master/D22Z/mail.py
        python mai.py "[email protected]" "httpd service down" `cat /tmp/apache.err`

        exit

    fi  
}
    
while :
do
    t_n=`ps -C httpd --no-heading |wc -l`
    if [ $t_n -ge 500 ]
    then
        /usr/local/apache2/bin/apachectl restart 
        if [ $? -ne 0 ]
        then
            check_service
        fi
        sleep 60
    fi
    sleep 10
done

 

103、用shell脚本实现如下需求:
添加user_00 - user_09 10个用户,并且给他们设置一个随机密码,密码要求10位包含大小写字母以及数字,注意需要把每个用户的密码记录到一个日志文件里。

提示: 
1. 随机密码使用命令 mkpasswd
2. 在脚本中给用户设置密码,可以使用echo 然后管道passwd命令

#!/bin/bash
for i in `seq -w 00 09`
do
    useradd user_$i
    p=`mkpasswd -s 0 -l 10`
    echo "user_$i $p" >>/tmp/user0_9.pass
    echo $p |passwd --stdin user_$i
done

 

104、输入数字执行对应命令

写一个脚本实现如下功能:  输入一个数字,然后运行对应的一个命令。显示命令如下:*cmd meau**  1---date 2--ls 3--who 4--pwd
当输入1时,会运行date, 输入2时运行ls, 依此类推。

#!/usr/bin/env bash

echo "**********cmd menu***********"

cmdTip=(

     "1--date"

      "2--ls"

      "3--who"

       "4--pwd"

)

for tip in ${cmdTip[@]};

do

    echo ${tip}

done

cmd=(

      "date"

       "ls"

       "who"

        "pwd"

)

read -p "Please enter the nature index of the cmd(DEFAULT 1):" num

echo ${num}

if [ -z ${num} ];then

    num=1

fi

echo $(${cmd[num-1]})

exit 0

 

105、用shell打印下面这句话中字母数小于6的单词。
Bash also interprets a number of multi-character options.

#!/bin/bash

for s in Bash also interprets a number of multi-character options

do 

    n=`echo $s|wc -c`

    if [ $n -lt 6 ]

        then echo $s

    fi

done

 

106、写一个脚本

创建一个函数,能接受两个参数:

1).第一个参数为URL,即可下载的文件;第二个参数为目录,即下载后保存的位置;

2).如果用户给的目录不存在,则提示用户是否创建;如果创建就继续执行,否则,函数返回一个51的错误值给调用脚本;

3).如果给的目录存在,则下载文件;下载命令执行结束后测试文件下载成功与否;如果成功,则返回0给调用脚本,否则,返回52给调用脚本;

[root@localhost tmp]# cat downfile.sh
#!/bin/bash
url=$1
dir=$2
download()
{
cd $dir >> /dev/null 2>&1
if [ $? -ne 0 ];then
 read -p "$dir No such file or directory,create?(y/n)" answer
if [ "$answer" == "y" ];then
  mkdir -p $dir
  cd $dir
  wget $url 1> /dev/null 2>&1
 else
  return "51"
 fi
fi
if [ $? -ne 0 ]; then
 return "52"
fi
}
download $url $dir
echo $

 

107、写一个脚本

1、创建一个函数,可以接受一个磁盘设备路径(如/dev/sdb)作为参数;在真正开始后面步骤之前提醒用户有危险,并让用户选择是否继续;而后将此磁盘设备上的所有分区清空(提示,使用命令dd if=/dev/zero of=/dev/sdb bs=512 count=1实现,注意其中的设备路径不要写错了;

如果此步骤失败,返回67给主程序;

接着在此磁盘设备上创建两个主分区,一个大小为100M,一个大小为1G;如果此步骤失败,返回68给主程序;

格式化此两分区,文件系统类型为ext3;如果此步骤失败,返回69给主程序;

如果上述过程都正常,返回0给主程序;

2、调用此函数;并通过接收函数执行的返回值来判断其执行情况,并将信息显示出来;

local Darray=(`ls /dev/sd[a-z]`)
for i in ${Darray};do
[[ "$i" == "$1" ]] && Sd=$i &&break
done
else
return66
fi


#当匹配成功,进入选择,告诉用户,是否继续,输错的话进入无限循环,当用户选择
Y,则清空目标分区,且跳出while循环
while :;do
read -p "Warning!!!This operation will clean $Sd data.Next=y,
Quit=n [y|n]:" Choice
case $Choice in
y)
dd if=/dev/zero of=$Sd bs=512 count=1 &> /dev/null &&break ||
return 67 ;;
n)
exit 88 ;;
*)
echo "Invalid choice,please choice again." ;;
esac
done

使用echo传递给fdisk进行分区,如果此命令失败,则跳转出去,错误值68,需要注意的是,有时候这个返回值很诡异,笔者之前成功与否都是返回的1,后来重启之后,就好了,如果慎重的话,可以对创建的分区,进行判断,不过就需要使用其他工具截取相关字段了,虽有些小麻烦,但无大碍

echo-e "n\np\n1\n\n+100M\nn\np\n2\n\n+1024M\nw\n"|
fdisk /dev/sdb&> /dev/null || return 68

格式化之前,让内核重新读取磁盘分区表,值得注意的是,有的系统版本,使用partprobe无效,譬如笔者的环境是rhel5.8,而rhel6.0以后,这个命令就很危险了,而使用partx -a /dev/sdb则效果更好…此项需慎重,如果格式化失败,则告知把失败的分区定义成变量,且跳出函数,并带出错误值69

`partprobe`
Part=`fdisk -l /dev/$Sd|tail -2|cut -d” ” -f1`
for M in ${Part};do
mke2fs -j $M &> /dev/null && ErrorPart=$M &&return 69
done
return 0
}

 

下面代码,调用函数,接收函数返回值,根据返回值进行判断哪里出错。

Disk_Mod $1
Res=$?
[ $Res-eq 0 ] && exit 0
[ $Res-eq 66 ] && echo "Error! Invalid input."
[ $Res-eq 67 ] && echo "Error! Command -> dd < - Faild."
[ $Res-eq 68 ] && echo "Error! Command -> fdisk < - Faild."
[ $Res-eq 69 ] && echo "Error! Command -> mke2fs < - Faild."

 

108、编写个shell脚本将当前目录下大于10K的文件转移到/tmp目录下

Q:主要是考察awk 这些的用法

#/bin/sh
#Programm :
# Using for move currently directory to /tmp
for FileName in `ls -l |awk ‘$5>10240 {print $9}’`
do
mv $FileName /tmp
done
ls -la /tmp
echo “Done! ”

 

109、编写shell脚本获取本机的网络地址。比如:本机的ip地址是:192.168.100.2/255.255.255.0,那么它的网络地址是192.168.100.1/255.255.255.0

方法一:

#!/bin/bash
#This script print ip and network
file=”/etc/sysconfig/network-scripts/ifcfg-eth0″
if [ -f $file ] ;then
IP=`grep “IPADDR” $file|awk -F”=” ‘{ print $2 }’`
MASK=`grep “NETMASK” $file|awk-F”=” ‘{ print $2 }’`
echo “$IP/$MASK”
exit 1
fi

方法二:

#!/bin/bash
#This programm will printf ip/network
#
IP=`ifconfig eth0 |grep ‘inet ‘ |sed ’s/^.*addr://g’|sed ’s/ Bcast.*$//g’`
NETMASK=`ifconfig eth0 |grep ‘inet ‘|sed ’s/^.*Mask://g’`
echo “$IP/$NETMASK”
exit

 

110、字符串替换命令                       

:s/well/good/                           替换当前行第一个well 为 good

:s/well/good/g                         替换当前行所有well 为 good

:n,$s/well/good/                      替换第 n 行开始到最后一行中每一行的第一个 well 为 good

:n,$s/well/good/g                   替换第 n 行开始到最后一行中每一行所有 well 为 good

n 为数字,若 n 为 .,   表示从当前行开始到最后一行

:%s/well/good/                     (等同于 :g/well/s//good/) 替换每一行的第一个 well 为 good

:%s/well/good/g                   (等同于 :g/well/s//good/g) 替换每一行中所有 well 为 good

特殊符号转义:可以使用#作为分隔符,此时中间出现的 / 不会作为分隔符

:s#well/#good/#                替换当前行第一个 well/ 为 good/

:%s#/usr/bin#/bin#g                可以把文件中所有路径/usr/bin换成/bin

111、删除多行                  

删除多行步骤如下:

1. 首先要显示对应的行数这样方能知道从第几行到第几行删除

: set nu

2. 按Esc键退出,在命令行中输入:190,6233d(即[190 , 6233]都删除掉)

如果想要情况整个文件内容,在直接运行以下命令:

清空文件内容:> log.txt

112、 行位定位           

直接定位到最后一行:

按Esc键退出,在命令行中输入: G

直接定位到第一行:

按Esc键退出,在命令行中输入: 1 G

直接定位到某一行:(第17行)

按Esc键退出,在命令行中输入:17 G

113、复制一行或多行             

<1. 复制一行

yy   复制当前行

p   粘贴

<2. 复制多行

7yy  从当前行开始复制7行

p   粘贴

 

114、grep 的用法         

<1. 显示匹配的后n行    (after)

grep -A n

<2. 显示匹配的前n行    (before)

grep -B n

<3. 显示匹配的前后n行 (context)

grep -C n

<4. 忽略大小写

grep -i str

115、

 

116、

117、

 

Shell脚本处理浮点数的运算和比较实例

1. 用bc来处理计算(包括整型和浮点计算)

bc – An arbitrary precision calculator language
(1). 通常在Bash脚本中使用bc的范例格式为:
variable=$(echo “OPTIONS; OPERATIONS” | bc [options]) 即:echo “[选项];操作” | bc [选项]
(2). 在下面的脚本中,提到在第一个选项中,“scale”变量表示输出中小数点后的精度,可以用于控制计算结果的精度;“ibase”和“obase”分别表示输入和输出数据的进制,可以用于数值进制的转换。
(3). 浮点数的比较,如“if [ $(echo "$big > $small" | bc) -eq 1 ]”,将一个逻辑判断式用管道传给bc。如果结果为真则输出1,否则输出0,然后就可以利用这个结果进行进一步的操作了。
(4). bc本来是用一个文件作为输入进行计算的(后面也有演示),所以可以将很复杂的计算写到文件中,然后让bc工具去处理到处计算结果。
注意一下:在使用除法运算符/时,要想保留小数,需要自己设置scale,否则默认时scale,小数点后时0位。

2. 使用awk来处理浮点计算和浮点数比较

不解释过多了,写了示例脚本如下,看懂了这个就会知道怎么处理浮点计算和浮点数比较了。

Shell脚本介绍(资源)_第25张图片

执行的结果如下:

Shell脚本介绍(资源)_第26张图片

另外,bc处理一个文件中的计算逻辑,演示如下:

Shell脚本介绍(资源)_第27张图片

请“man bc”查看详情;同样,请“man awk”。

 

Bash经典用法及其案例

一、条件选择、判断

(1)条件选择if

1、用法格式

if 判断条件 1 ; then

  条件为真的分支代码

elif 判断条件 2 ; then

  条件为真的分支代码

elif 判断条件 3 ; then

  条件为真的分支代码

else

  以上条件都为假的分支代码

fi

逐条件进行判断,第一次遇为“真”条件时,执行其分支,而后结束整个if。

2、经典案例:

① 判断年纪

Shell脚本介绍(资源)_第28张图片

分析:请输入年纪,先判断输入的是否含有除数字以外的字符,有,就报错;没有,继续判断是否小于150,是否大于18。

② 判断分数

Shell脚本介绍(资源)_第29张图片

分析:请输入成绩,先判断输入的是否含有除数字以外的字符,有,就报错;没有,继续判断是否大于100,是否大于85,是否大于60。

(2)条件判断 case

1、用法格式

case $name in;

PART1)

  cmd

  ;;

PART2)

  cmd

  ;;

*)

  cmd

  ;;

esac

注意:case 支持glob 风格的通配符:

  *: 任意长度任意字符

  ?: 任意单个字符

  [] :指定范围内的任意单个字符

  a|b: a 或b

2、案例:

判断yes or no

Shell脚本介绍(资源)_第30张图片

分析:请输入yes or no,回答Y/y、yes各种大小写组合为yes;回答N/n、No各种大小写组合为no。

二、四个循环

(1)for

1、用法格式

① for name in 列表 ;do

  循环体

done

② for (( exp1; exp2; exp3 )) ;do

  cmd

done

Shell脚本介绍(资源)_第31张图片

exp1只执行一次,相当于在for里嵌了while 

③ 执行机制:依次将列表中的元素赋值给“变量名”; 每次赋值后即执行一次循环体; 直到列表中的元素耗尽,循环结束

列表的表示方法,可以glob 通配符,如{1..10} 、*.sh ;也可以变量引用,如: `seq 1 $name`

2、案例:

① 求出(1+2+...+n)的总和

Shell脚本介绍(资源)_第32张图片

分析:sum初始值为0,请输入一个数,先判断输入的是否含有除数字以外的字符,有,就报错;没有判断是否为0,不为0进入for循环,i的范围为1~输入的数,每次的循环为sum=sum+i,循环结束,最后输出sum的值。

② 求出(1+2+...+100)的总和

Shell脚本介绍(资源)_第33张图片

分析:i=1,num=0;当i<=100,进入循环,若i÷2取余=1,则sum=sum+i,i=i+1。

(2)while

1、用法格式

while 循环控制条件 ;do

  循环

done

 循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;条件为“true” ,则执行一次循环;直到条件测试状态为“false” 终止循环

2、特殊用法(遍历文件的每一行):

while read line; do控制变量初始化

  循环体

done < /PATH/FROM/SOMEFILE

cat /PATH/FROM/SOMEFILE | while read line; do

  循环体

done

依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line

3、案例:

① 100以内所有正奇数之和

Shell脚本介绍(资源)_第34张图片

分析:sum初始值为0,i的初始值为1;请输入一个数,先判断输入的是否含有除数字以外的字符,有,就报错;没有当i<100时,进入循环,判断 i÷2取余 是否不为0,不为0时为奇数,sum=sum+i,i+1,为0,i+1;循环结束,最后输出sum的值。

(3)until 循环

1、用法

unitl 循环条件 ;do

  循环

done

进入条件:循环条件为true ;退出条件:循环条件为false;刚好和while相反,所以不常用,用while就行。

   2、案例

监控xiaoming用户,登录就杀死

Shell脚本介绍(资源)_第35张图片

分析:每隔0.5秒扫描,直到发现xiaoming用户登录,杀死这个进程,退出脚本,用于监控用户登录。 

(4)select 循环与菜单

1、用法

select variable in list

do

  循环体命令

done

① select 循环主要用于创建菜单,按数字顺序排列的示菜单项将显示在标准错误上,并显示PS3 提示符,等待用户输入

② 用户输入菜单列表中的某个数字,执行相应的命令

③ 用户输入被保存在内置变量 REPLY 中

④ select 是个无限循环,因此要记住用 break 命令退出循环,或用 exit 按 命令终止脚本。也可以按 ctrl+c退出循环

⑤ select 和 经常和 case 联合使用

⑥ 与for循环类似,可以省略 in list, 此时使用位置参量

2、案例:

生成菜单,并显示选中的价钱

Shell脚本介绍(资源)_第36张图片

分析:PS3是select的提示符,自动生成菜单,选择5break退出循环。

Shell脚本介绍(资源)_第37张图片

三、循环里的一些用法

(1)循环控制语句

continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断;最内层为第1层

break [N]:提前结束第N层循环,最内侧为第1层

 例:while CONDTITON1; do

  CMD1

if CONDITION2; then

  continue / break

fi

  CMD2

done

2、案例:

① 求(1+3+...+49+53+...+100)的和

Shell脚本介绍(资源)_第38张图片

分析:做1+2+...+100的循环,当i=51时,跳过这次循环,但是继续整个循环,结果为:sum=2449

② 求(1+3+...+49)的和

Shell脚本介绍(资源)_第39张图片

分析:做1+2+...+100的循环,当i=51时,跳出整个循环,结果为:sum=625

(2)循环控制shift命令

1、作用

用于将参数列表list左移指定次数,最左端的那个参数就从列表中删除,其后边的参数继续进入循环

2、案例:

① 创建指定的多个用户

Shell脚本介绍(资源)_第40张图片

分析:如果没有输入参数(参数的总数为0),提示错误并退出;反之,进入循环;若第一个参数不为空字符,则创建以第一个参数为名的用户,并移除第一个参数,将紧跟的参数左移作为第一个参数,直到没有第一个参数,退出。

② 打印直角三角形的字符

Shell脚本介绍(资源)_第41张图片

Shell脚本介绍(资源)_第42张图片

(3)返回值结果

true 永远返回成功结果

: null command ,什么也不干,返回成功结果

false 永远返回错误结果

创建无限循环

while true ;do

  循环体

done 

(4)循环中可并行执行,使脚本运行更快

1、用法

for name in 列表 ;do

  {

  循环体

  }&

done

wait

2、实例:

搜寻自己指定ip(子网掩码为24的)的网段中,UP的ip地址

Shell脚本介绍(资源)_第43张图片

分析:请输入一个IP地址例192.168.37.234,如果格式不是0.0.0.0 则报错退出;正确则进入循环,IP变量的值为192.168.37.  i的范围为1-254,并行ping 192.168.37.1-154,ping通就输出此IP为UP。直到循环结束。

四、信号捕获trap

1、用法格式

trap ' 触发指令' 信号,自定义进程收到系统发出的指定信号后,将执行触发指令,而不会执行原操作

trap '' 信号,忽略信号的操作

trap '-' 信号,恢复原信号的操作

trap -p,列出自定义信号操作

信号可以3种表达方法:信号的数字2、全名SIGINT、缩写INT

2、常用信号:

1) SIGHUP: 无须关闭进程而让其重读配置文件

2) SIGINT: 中止正在运行的进程;相当于Ctrl+c

3) SIGQUIT: 相当于ctrl+\

9) SIGKILL: 强制杀死正在运行的进程

15) SIGTERM :终止正在运行的进程(默认为15)

18) SIGCONT :继续运行

19) SIGSTOP :后台休眠

9 信号,强制杀死,捕获不住

3、案例:

① 打印0-9,ctrl+c不能终止

Shell脚本介绍(资源)_第44张图片

分析:i=0,当i<10,每休眠1秒,i+1,捕获2信号,并执行echo press ctrl+c

分析:i=0,当i<10,每休眠1秒,i+1,捕获2信号,并执行echo press ctrl+c

Shell脚本介绍(资源)_第45张图片

② 打印0-3,ctrl+c不能终止,3之后恢复,能终止

Shell脚本介绍(资源)_第46张图片

分析:i=0,当i<3,每休眠1秒,i+1,捕获2信号;i>3时,解除捕获2信号。

Shell脚本介绍(资源)_第47张图片

五、脚本小知识

1、生成随机字符 cat /dev/urandom

  生成8个随机大小写字母或数字 cat /dev/urandom |tr -dc [:alnum:] |head -c 8

2、生成随机数 echo $RANDOM

  确定范围 echo $[RANDOM%7] 随机7个数(0-6)

       echo $[$[RANDOM%7]+31] 随机7个数(31-37)

3、echo打印颜色字

echo -e "\033[31malong\033[0m" 显示红色along

echo -e "\033[1;31malong\033[0m" 高亮显示红色along

echo -e "\033[41malong\033[0m" 显示背景色为红色的along

echo -e "\033[31;5malong\033[0m" 显示闪烁的红色along

color=$[$[RANDOM%7]+31]

echo -ne "\033[1;${color};5m*\033[0m" 显示闪烁的随机色along

脚本

1、9x9乘法表

Shell脚本介绍(资源)_第48张图片

Shell脚本介绍(资源)_第49张图片

2、彩色等腰三角形

Shell脚本介绍(资源)_第50张图片

Shell脚本介绍(资源)_第51张图片

3、国际象棋棋盘

Shell脚本介绍(资源)_第52张图片

Shell脚本介绍(资源)_第53张图片

常用shell语句

if语句

一、条件测试的表达式:

    [ expression ]  括号两端必须要有空格

    [[ expression ]] 括号两端必须要有空格

    test expression

 

组合测试条件:

-a: and

-o: or

!:  非

 

二、整数比较:

-eq 测试两个整数是否相等

-ne 测试两个整数是否不等

-gt 测试一个数是否大于另一个数

-lt 测试一个数是否小于另一个数

-ge 大于或等于

-le 小于或等于

 

三、命令间的逻辑关系

逻辑与:&&

        第一个条件为假 第二个条件不用在判断,最总结果已经有

        第一个条件为真,第二个条件必须得判断

 

逻辑或:||

 

四、字符串比较

== 等于  两边要有空格

!= 不等

>  大于

<  小于

 

五、文件测试

-z string 测试指定字符是否为空,空着真,非空为假

-n string 测试指定字符串是否为不空,空为假 非空为真

-e file 测试文件是否存在

-f file 测试文件是否为普通文件

-d file 测试指定路径是否为目录

-r file 测试文件对当前用户是否可读

-w file 测试文件对当前用户是否可写

-x file 测试文件对当前用户是都可执行

-z  是否为空  为空则为真

-a  是否不空

这里,如果then不写在if后面,if后面就不用分好了;还有,末尾记得fi结尾呀!

 

SHELL实战

  1. SHELL实战Nginx WEB源码安装

#!/bin/bash

#20179615:00:17

#auto install nginx web

#by author www.jfedu.net

########################

rm -rf /usr/local/nginx/

wget -c http://nginx.org/download/nginx-1.12.1.tar.gz

tar -xzvf nginx-1.12.1.tar.gz

cd  nginx-1.12.1/

./configure

make

make install

/usr/local/nginx/sbin/nginx

             2、SHELL编程实战Vsftpd虚拟用户

#!/bin/bash

#20179615:20:07

#auto config vsftpd user

#by author www.jfedu.net

####################

#Install Vsftpd Soft

yum install vsftpd* -y

#/etc/init.d/vsftp restart

service vsftpd restart

#Config vsftp virtual user

yum  install  pam  libdb-utils  libdb  --skip-broken  -y

touch /etc/vsftpd/ftpusers.txt

#echo "jfedu001

#123456">/etc/vsftpd/ftpusers.txt

cat>>/etc/vsftpd/ftpusers.txt<

jfedu001

123456

EOF

db_load  -T  -t  hash  -f  /etc/vsftpd/ftpusers.txt  /etc/vsftpd/vsftpd_login.db

chmod  700  /etc/vsftpd/vsftpd_login.db

chmod  700  /etc/vsftpd/ftpusers.txt

cat>/etc/pam.d/vsftpd<

auth      required        pam_userdb.so   db=/etc/vsftpd/vsftpd_login

account   required        pam_userdb.so   db=/etc/vsftpd/vsftpd_login

EOF

#Create vsftpd system user

useradd    -s   /sbin/nologin    ftpuser

cat>>/etc/vsftpd/vsftpd.conf<

#config virtual user FTP

pam_service_name=vsftpd

guest_enable=YES

guest_username=ftpuser

user_config_dir=/etc/vsftpd/vsftpd_user_conf

virtual_use_local_privs=YES

EOF

mkdir  -p    /etc/vsftpd/vsftpd_user_conf/

touch /etc/vsftpd/vsftpd_user_conf/jfedu001

cat>/etc/vsftpd/vsftpd_user_conf/jfedu001 <

local_root=/home/ftpuser/jfedu001

write_enable=YES

anon_world_readable_only=YES

anon_upload_enable=YES

anon_mkdir_write_enable=YES

anon_other_write_enable=YES

EOF

#Create virtual user basedir

mkdir -p /home/ftpuser/jfedu001

chown -R ftpuser:ftpuser /home/ftpuser

service vsftpd restart

service firewalld stop

setenforce 0

#Vsftpd config done.

 

注意 :                

1、脚本里为什么要另外在path 加环境变量

答:在cron里执行时,cron的PATH并不全,所以额外定义一下会更保险

 

2、exec这行在这里的作用是什么

这行用来定义输出内容到哪个文件

 

3、请问:本地保存一周,远程保存一个月是怎么实现的! 每天凌晨三点执行一次,每次均拷贝远程地址,远程拷贝的前一天数据会被覆盖吗?

答 :本地一周,就用那个 date +%w 实现,一周不是7天么。 远程一个月,是需要加一个任务计划,find 找一下一个月以前的文件,然后删除掉

 

4、shell脚本不执行

  问题:某天研发同事找我说帮他看看他写的shell脚本,死活不执行,报错。我看了下,脚本很简单,也没有常规性的错误,报“:badinterpreter:Nosuchfileordirectory”错。
    看这错,我就问他是不是在windows下编写的脚本,然后在上传到linux服务器的……果然。
    原因:在DOS/windows里,文本文件的换行符为rn,而在*nix系统里则为n,所以DOS/Windows里编辑过的文本文件到了*nix里,每一行都多了个^M。
    解决:
    1)重新在linux下编写脚本;
    2)vi:%s/r//g:%s/^M//g(^M输入用Ctrl+v,Ctrl+m)
    附:sh-x脚本文件名,可以单步执行并回显结果,有助于排查复杂脚本问题。

 

5、Shell脚本是什么、它是必需的吗?

答:一个Shell脚本是一个文本文件,包含一个或多个命令。作为系统管理员,我们经常需要使用多个命令来完成一项任务,我们可以添加这些所有命令在一个文本文件(Shell脚本)来完成这些日常工作任务。

 

6、什么是默认登录shell,如何改变指定用户的登录shell

答:在Linux操作系统,“/bin/bash”是默认登录shell,是在创建用户时分配的。使用chsh命令可以改变默认的shell。示例如下所示:

# chsh <用户名> -s <新shell>
# chsh linuxtechi -s /bin/sh

 

7、可以在shell脚本中使用哪些类型的变量?

答:在shell脚本,我们可以使用两种类型的变量:

  • 系统定义变量

  • 用户定义变量

系统变量是由系统系统自己创建的。这些变量通常由大写字母组成,可以通过“set”命令查看。

用户变量由系统用户来生成和定义,变量的值可以通过命令“echo $<变量名>”查看。

 

8、如何将标准输出和错误输出同时重定向到同一位置?

答:这里有两个方法来实现:

方法一:

2>&1 (如# ls /usr/share/doc > out.txt 2>&1 )

方法二:

&> (如# ls /usr/share/doc &> out.txt )

 

9、shell脚本中“if”语法如何嵌套?

答:基础语法如下:

if [ 条件 ]
then
命令1
命令2
…..
else
if [ 条件 ]
then
命令1
命令2
….
else
命令1
命令2
…..
fi
fi

 

10、shell脚本中“$?”标记的用途是什么?

答:在写一个shell脚本时,如果你想要检查前一命令是否执行成功,在if条件中使用“$?”可以来检查前一命令的结束状态。简单的例子如下:

root@localhost:~# ls /usr/bin/shar
/usr/bin/shar
root@localhost:~# echo $?
0

如果结束状态是0,说明前一个命令执行成功。

root@localhost:~# ls /usr/bin/share
ls: cannot access /usr/bin/share: No such file or directory
root@localhost:~# echo $?
2

如果结束状态不是0,说明命令执行失败。

 

11、在shell脚本中如何比较两个数字 ?

答:在if-then中使用测试命令( -gt 等)来比较两个数字,例子如下:

#!/bin/bash
x=10
y=20
if [ $x -gt $y ]
then
echo “x is greater than y”
else
echo “y is greater than x”
fi

 

12、shell脚本中break命令的作用 ?

答:break命令一个简单的用途是退出执行中的循环。我们可以在while和until循环中使用break命令跳出循环。

 

13、shell脚本中continue命令的作用 ?

答:continue命令不同于break命令,它只跳出当前循环的迭代,而不是整个循环。continue命令很多时候是很有用的,例如错误发生,但我们依然希望继续执行大循环的时候。

 

14、告诉我shell脚本中Case语句的语法 ?

答:基础语法如下:

case 变量 in
值1)
命令1
命令2
…..
最后命令
!!
值2)
命令1
命令2
……
最后命令
;;
esac

 

15、shell脚本中while循环语法 ?

答: 如同for循环,while循环只要条件成立就重复它的命令块。不同于for循环,while循环会不断迭代,直到它的条件不为真。基础语法:

while [ 条件 ]
do
命令…
done

 

16、 如何使脚本可执行 ?

答:使用chmod命令来使脚本可执行。例子如下:

# chmod a+x myscript.sh

 

17、“#!/bin/bash”的作用 ?

答:#!/bin/bash是shell脚本的第一行,称为释伴(shebang)行。这里#符号叫做hash,而! 叫做 bang。它的意思是命令通过 /bin/bash 来执行。

 

18、for循环的基础语法:

for 变量 in 循环列表
do
命令1
命令2
….
最后命令
done

 

19、如何调试shell脚本 ?

答:使用'-x'参数(sh -x myscript.sh)可以调试shell脚本。另一个种方法是使用‘-nv’参数( sh -nv myscript.sh)。

 

20、shell脚本如何比较字符串?

答:test命令可以用来比较字符串。测试命令会通过比较字符串中的每一个字符来比较。

 

21、Bourne shell(bash) 中有哪些特殊的变量 ?

答:下面的表列出了Bourne shell为命令行设置的特殊变量。

内建变量    解释
$0    命令行中的脚本名字
$1    第一个命令行参数
$2    第二个命令行参数
…..    …….
$9    第九个命令行参数
$#    命令行参数的数量
$*    所有命令行参数,以空格隔开

 

22、在shell脚本中,如何测试文件 ?

答:test命令可以用来测试文件。基础用法如下表格:

Test         用法
-d 文件名    如果文件存在并且是目录,返回true
-e 文件名    如果文件存在,返回true
-f 文件名    如果文件存在并且是普通文件,返回true
-r 文件名    如果文件存在并可读,返回true
-s 文件名    如果文件存在并且不为空,返回true
-w 文件名    如果文件存在并可写,返回true
-x 文件名    如果文件存在并可执行,返回true

 

23、在shell脚本中,如何写入注释 ?

答:注释可以用来描述一个脚本可以做什么和它是如何工作的。每一行注释以#开头。例子如下:

#!/bin/bash
# This is a command
echo “I am logged in as $USER”

 

24、如何让 shell 就脚本得到来自终端的输入?

答:read命令可以读取来自终端(使用键盘)的数据。read命令得到用户的输入并置于你给出的变量中。例子如下:

# vi /tmp/test.sh
#!/bin/bash
echo ‘Please enter your name’
read name
echo “My Name is $name”
# ./test.sh

Please enter your name
LinuxTechi
My Name is LinuxTechi

 

25、如何取消变量或取消变量赋值 ?

答:“unset”命令用于取消变量或取消变量赋值。语法如下所示:

# unset <变量名>

 

26、如何执行算术运算 ?

答:有两种方法来执行算术运算:

1.使用expr命令

# expr 5 + 2

2.用一个美元符号和方括号($[ 表达式 ])例如:

test=$[16 + 4] ; test=$[16 + 4]

 

27、do-while语句的基本格式 ?

答:do-while语句类似于while语句,但检查条件语句之前先执行命令(LCTT 译注:意即至少执行一次。)。下面是用do-while语句的语法

do
{
命令
} while (条件)

 

 

28、在shell脚本如何定义函数呢 ?

答:函数是拥有名字的代码块。当我们定义代码块,我们就可以在我们的脚本调用函数名字,该块就会被执行。示例如下所示:

$ diskusage () { df -h ; }
译注:下面是我给的shell函数语法,原文没有
[ function ] 函数名 [()]
{
命令;
[return int;]
}


29、乘法口诀

# vi 1.py

#!/usr/bin/python

#

for i in xrange(1,10):

     for j in xrange(1,i+1):

           print "$s X %s = %s" %(i,j,i*j),

     print

# python 1.py

 

30、系统随机生成一个1-20的随机数

# vi 1.py

#/usr/bin/python
#coding:utf-8
print‘游戏规则:系统随机生成一个1-20的数字,你有6次机会,猜一下吧。’
import random
import sys
snum=random.randint(1,20)
#print snum
num=int(raw_input('请输入一个数字:'))
if num == snum:
     print '恭喜你,你猜对了。'
else:
      for i in xrange(1,7):
            if num ==snum:
                  print '恭喜你,猜对了。'
                  sys.exit()
            elif num > snum:
                  print '猜的数字太大了。'
            elif num > snum:
                  print '猜的数字太小了。'
            if i == 6:
                  print '6次机会用完了'
                  sys.exit()
            num=int(raw_input('猜错了,再猜一次吧:'))

# python 1.py

Shell脚本介绍(资源)_第54张图片

 

31、查看磁盘空间大小

#!/usr/bin/python

#coding:utf-8

with open('/proc/meminfo') as fd:

     for line in fd:

          if line.startswith('MemTotal'):

             total=linesplit()[1]

             contine

          if line.startswith('MemFree'):

             total=linesplit()[1]

             break

#print total.free

print "总内存数"+"%.2f" %(int(total)/1024.0)+'M内存'

print "剩余"+"%.2f" %(int(total)/1024.0)+'M内存'

memused=int(total)-int(free)

print "使用"+"%.2f" %(int(memused)/1024.0)+'M内存'

print "占用"+"%.2f" %(int(memused)/1.0/int(total))+'%'

#python men.py

Shell脚本介绍(资源)_第55张图片

 

32什么时候不使用shell脚本

答 : 需要大规模的文件操作

需要多维数组的支持

需要直接操作系统硬件

 

33、test  <测试表达式>与[ <测试表达式> ]等价

如果flie文件存在,则输出true,否则(||)输出false。

Shell脚本介绍(资源)_第56张图片

-f              #文件存在且为普通文件则表达式成立

-z              #如果测试字符串的长度为0,则表达式成立

&&、||、>、<等操作符可以应用于[[ ]]中,但不能应用于[]中,在[]中一般使用-a、-o、-gt(用于整数)、-lt(用于整数)。

例:使用read传入数字等于1,就打印1。如果等于2,就打印2。如果不等于1也不等于2,就提示错误。

Shell脚本介绍(资源)_第57张图片

 

34、使用read读入方式比较两个整数的大小。

Shell脚本介绍(资源)_第58张图片

Shell脚本介绍(资源)_第59张图片

Shell脚本介绍(资源)_第60张图片

 

35、打印选择菜单,按照选择项一键安装不同的WEB服务。

代码:

#!/bin/sh

cat <

    1.[install lamp]

    2.[install lnmp]

    3.[exit]

please input the num:

EOF

sh_path=/server/scripts

[ ! -d ${sh_path} ] && {

        mkdir -p ${sh_path}

}

read num

expr ${num} + 1 &>/dev/null;

[ $? -ne 0 ] && {

echo "please input the num is {1|2|3}!";

exit 0;

}

[[ ! ${num} = [1-3] ]] && {

        echo "please input the num is {1|2|3}!";

        exit 1;

}

[ ${num} -eq 1 ] && {

        echo "start installing lamp:";

        [ -x ${sh_path}/lamp.sh  ] || {

        echo "${sh_path}/lamp.sh does not exist or can't be exe.";

        exit 2;

        }

        ${sh_path}/lamp.sh;

        exit $?;

}

[ ${num} -eq 2 ]  && {

        echo "start installing lnmp:";

        [ -x ${sh_path}/lnmp.sh ]  || {

        echo "${sh_path}/lnmp.sh does't exist or can't be exec.";

        exit 3;

        }

        ${sh_path}/lnmp.sh;

        exit $?;

}

[ ${num} -eq 3 ]  && {

        echo "exit"

        exit 4;

}

执行结果:

 

36、编写shell脚本,批量生成30个密码

vi mkpasswd.sh

#!/bin/bash

i=1

echo "########kim by 51cto.com##########" >/tmp/passwd.txt

while [ $i -le 30 ];do

/usr/bin/mkpasswd -l 14 -s 2 -c 3 -C 3 -d 4 >>/tmp/passwd.txt

let i+=1

done

exit;

mkpasswd参数详解

-l #      (length of password, default = 7)

指定密码的长度,默认是7位数

-d #      (min # of digits, default = 2)

指定密码中数字最少位数,默认是2位

-c #      (min # of lowercase chars, default = 2)

指定密码中小写字母最少位数,默认是2位

-C #      (min # of uppercase chars, default = 2)

指定密码中大写字母最少位数,默认是2位

-s #      (min # of special chars, default = 1)

指定密码中特殊字符最少位数,默认是1位

 

37、写一个shell脚本来得到当前的日期,时间,用户名和当前工作目录。

#!/bin/bash 
echo "Hello, $LOGNAME" 
echo "Current date is `date`" 
echo "User is `who i am`" 
echo "Current directory `pwd`"

# chmod 755 21.sh 
# ./21.sh

Shell脚本介绍(资源)_第61张图片


38、比较数字大小 

#!/bin/bash  
test $1 -gt  $2 && echo $1  
test $1 -lt  $2 && echo $2  
test $1 -eq  $2  && echo $1=$2 

Shell脚本介绍(资源)_第62张图片

 

39、

 

40、

 

 

参考链接  :

http://www.cnblogs.com/along21/p/7519710.html

五分钟搞定Bash功能与使用技巧 : https://mp.weixin.qq.com/s/qxyV0Ye9yIqkUA7V8Kx0wQ

17个案例带你3分钟搞定Linux正则表达式https://mp.weixin.qq.com/s/bAc-coGwnKxvQHOkqZRJAQ

Shell编程:shell脚本的条件测试  :    https://mp.weixin.qq.com/s?__biz=MzU4MjUzNDMyOQ==&mid=2247483848&idx=1&sn=2d3165fefd1573e3f46b7133bc786982&chksm=fdb7941ecac01d0841a39cac28392a613d466ba88b4d7168583d5dedfddc845e4fb0254833a4&scene=21#wechat_redirect

 

资料:

shell脚本常用知识 : http://ju.outofmemory.cn/entry/225010

如何让执行到中途中断的程序继续自动执行? : http://www.voidcn.com/code/p-noktlbvp-p.html

重启Tomcat的shell脚本  : http://www.voidcn.com/code/p-gejgbzas-h.html

shell产生随机数七种方法 : http://blog.sina.com.cn/s/blog_638b7ebb0102vurp.html

 

 

linux 网卡流量监控 (脚本)  : http://www.voidcn.com/code/p-glpuwwga-p.html

Shell 入门指南 :  https://wdxtub.com/2016/08/02/shell-guide/

《shell脚本系统监控-------邮件告警》   :   http://blog.51cto.com/leoheng/1955773

编写了一个ssh管理并自动登录shell脚本  :  https://www.jianshu.com/p/789287ba0e6b

shell脚本加密 | shc            :  https://www.jianshu.com/p/7f3db04c0786

shell脚本进阶 详解及其实例(一)   :  https://www.cnblogs.com/keerya/p/7530802.html

Shell编程:shell脚本的条件测试     :    https://mp.weixin.qq.com/s?__biz=MzU4MjUzNDMyOQ==&mid=2247483892&idx=1&sn=8490118c4babd6ff9582d80507ecee14&chksm=fdb79422cac01d34ac60c528dd8acd538242d857b9b51a6fea177cb402d7ed9c0f51d7a8648f&scene=21#wechat_redirect

If条件语句-监测系统内存报警    :   http://mp.weixin.qq.com/s?__biz=MzU4MjUzNDMyOQ==&mid=2247483877&idx=1&sn=87eb31b447ce9c995e5e8861d9b9dfc8&chksm=fdb79433cac01d252b39e7c5447a999674b988b1d5b8706b3cfde8ddb38665688a84111a8b71&scene=21#wechat_redirect

 

Shell学习---Shell脚本的静态检查工具shellcheck           :     https://www.cnblogs.com/ftl1012/p/9568635.html

Linux 下Shell的学习之优秀博主推荐          :       https://www.cnblogs.com/ftl1012/p/9567984.html

Linux 下Shell的学习3-优秀demo            :       https://www.cnblogs.com/ftl1012/p/9314069.html

Linux 下shell中exec解析        : https://www.cnblogs.com/ftl1012/p/9310536.html

Linux 下Shell的学习2       :     https://www.cnblogs.com/ftl1012/p/9310505.html

Linux 下Shell的学习     :   https://www.cnblogs.com/ftl1012/p/shell.html

 

shell脚本_查看网段中的存活主机和MAC地址              :      http://blog.51cto.com/11638832/1855990

shell脚本_while、if脚本语句_价格竞猜        :      http://blog.51cto.com/11638832/1855989

根据字段状态删除指定目录文件的shell脚本 荐            :  http://blog.51cto.com/liangey/1641878

SHELL网络爬虫实例剖析 荐         ::   http://blog.51cto.com/nolinux/1552472

如何用SHELL写好网络爬虫 荐       :       http://blog.51cto.com/nolinux/1550976

SHELL(20篇) : https://blog.csdn.net/stpeace/article/category/6952361

Shell中的循环语句for、while、until实例讲解  : https://www.jb51.net/article/50643.htm

笔记 | 史上最全的正则表达式 : https://mp.weixin.qq.com/s/SA3OnfZD-cFVi7IVfKwKnw

shell去掉文件中空行(空白行)的方法详解  : https://www.jb51.net/article/42288.htm

 

 

转载于:https://my.oschina.net/u/3803405/blog/1816950

你可能感兴趣的:(Shell脚本介绍(资源))