2019独角兽企业重金招聘Python工程师标准>>>
导语 : 在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地址的行。
以下通过几个简单的实例演示重定向的使用方法:
Bash快捷键
花括号{}的使用
一、SHELL编程概念
1)SHELL、SHELL编程、SHELL脚本、SHELL命令区别
Shell命令解释器,是用户和操作系统沟通的桥梁;
Shell编程,基于Shell解释器实现软件自动化功能;
Shell编程语言是非类型的解释型语言。
SHELL脚本,实现Shell编程实体;
SHELL命令,具体实现某个功能、内容的指令;
SHELL变量两种:局部变量和环境变量,赋值符号=,使用$符号引用
SHELL编程变量三种:系统变量、环境变量、用户变量
shel脚本变量类型 : 局部变量、环境变量、shell变量
元字符通常在Linux中分为两类 :
-
Shell元字符,由Linux Shell进行解析;
-
正则表达式元字符,由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编程四剑客(find、sed、awk、grep)功能及用途:
Find工具:主要用于文件、文件夹的查找,找到文件的路径;
Sed工具:非交互模式编辑器、vim交互式编辑器,用于文件内容修改;
Awk工具:主要用于对文件内容进行处理、输出预定的结果;
Grep工具:主要用于操作系统文件内容的查找,对文件的内容的操作,匹配文件中的关键词;
Find命令工具:
主要用于对操作系统文件路径的查找;
find path -option [ -print ] [ -exec -ok command ] { } \;
- find . 查找当前目录所有文件、文件夹;
- find / -name "test.txt"|xargs rm -rf {} \;查找test.txt文件并删除;
- find . -name "*.txt" -exec cp {} /root/ \;查找当前目录以.txt结尾文件,并且将该文件cp至/root目录;(推荐使用exec)
- 恢复/tmp/下文件、目录原来权限;
-
文件权限默认是:644
目录权限默认是:755
find . -type d -exec chmod 755 -R {} \;(\;结束标记)修改当前目录,类型是目录的权限改完默认权限;
find . -type f -exec chmod 644 -R {} \; 修改当前目录,类型是文件的权限改完默认权限;
- 查找当前目录文件大小,-size参数:find . -size +20M -a -size -200M -exec rm -rf {} \;
- find . -name "*.log" ! -name "access.log" ! -name "error.log" -size +30M -size -40M -type f
- 按天数、时间去查找文件及文件夹;
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
查找log文件,大于100M,权限644,去掉test1.log文件,修改时间小于30分钟
find . -name "*.log" -type f -size +100M -perm 644 ! -name "test1.log" -mtime -30 -mmin -1
拷贝到/tmp目录、在当前目录,只有一级目录
应用场景:
根据你的需求,假设网卡的配置文件:
eth0查找网卡的配置文件,修改IP;
恢复权限
恢复文档文件权限
find . -type f -exec chmod -R 644 {} \;
恢复目录权限
find . -type d -exec chmod -R 755 {} \;
把大于5M的文件文档,移到/tmp/目录
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
匹配IP地址
严格匹配IP地址
意思同上
shell变量为弱类型,定义变量不需要声明类型,但使用时需要明确变量大的类型,可以是使用Declare指定类型,Declare常见参数:
+/- "-"可用来指定变量的属性,“+”为取消变量所设的属性
-f 仅显示函数
r 将变量设置为只读
x 指定的变量会成为环境变量,可供shell以外的程序来使用。
i 指定类型为数值,字符串或运算符
SHELL变量详解
- 变量是一个可变的值,SHELL变量主要是为了减少重复引用;
- SHELL变量是弱类型,使用时直接=赋值即可,ABC=123,ABC是变量名称,123位变量的值;
- 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)
q 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独立于内核,它是链接内核和应用程序的桥梁。内核是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
使用命令:>>/var/www/html/phpinfo.php 追加到/var/www/html/phpinfo.php 中。
执行脚本的不同方式
第一种使用绝对路径执行 例如 : /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"
a
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
- SHELL编程实战优化
- SHELL脚本优化引入变量;
SHELL变量,是一个可变的值,跟常量是对应关系,常量是一个固定的值,变量可变;
变量相当于别名,xiaoming=110101199410234012,获取身份证ID号,$xiaoming;
- SHELL脚本引入if、for、while、case条件判断;
- 检查SHELL脚本功能、需求是否有缺陷;
- 检查SHELL脚本能否扩展,批量生产!
SHELL9个实例 :
1、 获取随机字符串或数字
获取随机8位字符串:
获取随机8位数字:
2 、定义一个颜色输出字符串函数
3、 批量创建用户
4 、检查软件包是否安装
5、 检查服务状态
6 、检查主机存活状态
方法1: 将错误IP放到数组里面判断是否ping失败三次
方法2: 将错误次数放到FAIL_COUNT变量里面判断是否ping失败三次
方法3: 利用for循环将ping通就跳出循环继续,如果不跳出就会走到打印ping失败
7 、监控CPU、内存和硬盘利用率
1)CPU
借助vmstat工具来分析CPU统计信息。
2)内存
3)硬盘
8 、批量主机磁盘利用率监控
前提监控端和被监控端SSH免交互登录或者密钥登录。
写一个配置文件保存被监控主机SSH连接信息,文件内容格式:IP User Port
9 、检查网站可用性
1)检查URL可用性
2)判断三次URL可用性
思路与上面检查主机存活状态一样。
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_numbersfi
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
2
#!/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
2
#!/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
fifi
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,内容如下:
请写出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来处理浮点计算和浮点数比较
不解释过多了,写了示例脚本如下,看懂了这个就会知道怎么处理浮点计算和浮点数比较了。
执行的结果如下:
另外,bc处理一个文件中的计算逻辑,演示如下:
请“man bc”查看详情;同样,请“man awk”。
Bash经典用法及其案例
一、条件选择、判断
(1)条件选择if
1、用法格式
if 判断条件 1 ; then
条件为真的分支代码
elif 判断条件 2 ; then
条件为真的分支代码
elif 判断条件 3 ; then
条件为真的分支代码
else
以上条件都为假的分支代码
fi
逐条件进行判断,第一次遇为“真”条件时,执行其分支,而后结束整个if。
2、经典案例:
① 判断年纪
分析:请输入年纪,先判断输入的是否含有除数字以外的字符,有,就报错;没有,继续判断是否小于150,是否大于18。
② 判断分数
分析:请输入成绩,先判断输入的是否含有除数字以外的字符,有,就报错;没有,继续判断是否大于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
分析:请输入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
exp1只执行一次,相当于在for里嵌了while
③ 执行机制:依次将列表中的元素赋值给“变量名”; 每次赋值后即执行一次循环体; 直到列表中的元素耗尽,循环结束
列表的表示方法,可以glob 通配符,如{1..10} 、*.sh ;也可以变量引用,如: `seq 1 $name`
2、案例:
① 求出(1+2+...+n)的总和
分析:sum初始值为0,请输入一个数,先判断输入的是否含有除数字以外的字符,有,就报错;没有判断是否为0,不为0进入for循环,i的范围为1~输入的数,每次的循环为sum=sum+i,循环结束,最后输出sum的值。
② 求出(1+2+...+100)的总和
分析: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以内所有正奇数之和
分析: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用户,登录就杀死
分析:每隔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、案例:
生成菜单,并显示选中的价钱
分析:PS3是select的提示符,自动生成菜单,选择5break退出循环。
三、循环里的一些用法
(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)的和
分析:做1+2+...+100的循环,当i=51时,跳过这次循环,但是继续整个循环,结果为:sum=2449
② 求(1+3+...+49)的和
分析:做1+2+...+100的循环,当i=51时,跳出整个循环,结果为:sum=625
(2)循环控制shift命令
1、作用
用于将参数列表list左移指定次数,最左端的那个参数就从列表中删除,其后边的参数继续进入循环
2、案例:
① 创建指定的多个用户
分析:如果没有输入参数(参数的总数为0),提示错误并退出;反之,进入循环;若第一个参数不为空字符,则创建以第一个参数为名的用户,并移除第一个参数,将紧跟的参数左移作为第一个参数,直到没有第一个参数,退出。
② 打印直角三角形的字符
(3)返回值结果
true 永远返回成功结果
: null command ,什么也不干,返回成功结果
false 永远返回错误结果
创建无限循环
while true ;do
循环体
done
(4)循环中可并行执行,使脚本运行更快
1、用法
for name in 列表 ;do
{
循环体
}&
done
wait
2、实例:
搜寻自己指定ip(子网掩码为24的)的网段中,UP的ip地址
分析:请输入一个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不能终止
分析:i=0,当i<10,每休眠1秒,i+1,捕获2信号,并执行echo press ctrl+c
分析:i=0,当i<10,每休眠1秒,i+1,捕获2信号,并执行echo press ctrl+c
② 打印0-3,ctrl+c不能终止,3之后恢复,能终止
分析:i=0,当i<3,每休眠1秒,i+1,捕获2信号;i>3时,解除捕获2信号。
五、脚本小知识
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乘法表
2、彩色等腰三角形
3、国际象棋棋盘
常用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实战
- SHELL实战Nginx WEB源码安装
#!/bin/bash
#2017年9月6日15: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
#2017年9月6日15: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),
# 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
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
32什么时候不使用shell脚本
答 : 需要大规模的文件操作
需要多维数组的支持
需要直接操作系统硬件
33、test <测试表达式>与[ <测试表达式> ]等价
如果flie文件存在,则输出true,否则(||)输出false。
-f #文件存在且为普通文件则表达式成立
-z #如果测试字符串的长度为0,则表达式成立
&&、||、>、<等操作符可以应用于[[ ]]中,但不能应用于[]中,在[]中一般使用-a、-o、-gt(用于整数)、-lt(用于整数)。
例:使用read传入数字等于1,就打印1。如果等于2,就打印2。如果不等于1也不等于2,就提示错误。
34、使用read读入方式比较两个整数的大小。
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 # chmod 755 21.sh #!/bin/bash 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 入门指南 : https://wdxtub.com/2016/08/02/shell-guide/ 《shell脚本系统监控-------邮件告警》 : http://blog.51cto.com/leoheng/1955773 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
echo "Hello, $LOGNAME"
echo "Current date is `date`"
echo "User is `who i am`"
echo "Current directory `pwd`"
# ./21.sh
38、比较数字大小
test $1 -gt $2 && echo $1
test $1 -lt $2 && echo $2
test $1 -eq $2 && echo $1=$2 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
编写了一个ssh管理并自动登录shell脚本 : https://www.jianshu.com/p/789287ba0e6b