shell (一)
Shell脚本简历
1.1什么是shell脚本
在解释shell脚本之前、我们来说下什么shell?
Shell是一个命令解释器、它在操作系统的最外层、负责直接与用户对话、把用户的输入解释给操作系统、并处理各种各样的操作系统的输出结果、输入到屏幕返回给用户、这种对话方式可以是交互式方式、(从键盘输入命令、可以立即得到shell的回应)、或shell非交互脚本方式
1、2什么是shell脚本?
当命令或语句不在命令行执行、而是通过一个程序文件执行时、改程序贝称为shell脚本或sehll程序、shell程序类似于DOS系统下的批处理程序(*.bat)。用户可以在shell脚本输入一系列的命令或命令语句、这些,命令、变量、和流程控制语句等有机会的结合在一起形成了一个功能强大的shell脚本。
查看系统shell
[root@mail2 ~]# echo $SHELL
/bin/bash
[root@mail2 ~]#
1.3shell脚本的建立
脚本的开头(第一行)、
一个规范的shell脚本的第一行会指出由那个程序(解释器)来执行脚本中的内容、在linux bash编程中,一般为
#!/bin/bash 或者/bin/sh
#!又称作幻数、在执行bash脚本的时候。内核会根据它来指定改用那个程序来解释脚本的内容、这一行必须在脚本顶端的第一行。如果不是第一行则为注释
1)开头加版权等信息
#date : 20:40 2017-03-22
#Author : jack ben
#mail :1249648969@qq.com
#Function : This backup mysql is ,,,
#version: 1.1
2)脚本中不用中文注释:
尽量用英文注释,防止本机或切换系统环境后中文乱码的困扰
3) 脚本以 .sh 为扩展名
例如:backup.sh
4)代码书写优秀习惯
1、成对内容的一次写出来,防止遗漏,如:
{} [] ‘’ “”
2、流程控制语句
If 条件内容
Then
内容
Fi
For循环格式一次完成
For
Do
内容
Done
提示:while和until等循环也是一样的。
二、shell变量基础及深入
1、变量可分为两类:环境变量(或全局变量) 和局部变量
环境变量也可称作全局变量,也可以在创建它的shell及其派生出来的任意子进程shell中使用、局部变量只能在创建他们的shell函数或脚本中使用、还有一些变量是用户创建的,其他的则是专用的shell变量。
2、环境变量用于定义shell的运行环境、保证shell命令的正确执行、shell通过环境变量来确定登陆用户名,命令路径、终端类型、登陆目录等、所有的环境变量都是系统全局变量。也可以用于所有子进程中、这包括编辑器、shell脚本和各类应用。
3、自定义环境变量(全局变量)
设置环境变量
如果想设置环境变量、就要在给变量赋值之后或设置变量时使用export命令、带-x 选项的declare内置命令也可以完成同样的功能。(注意:输出变量时不要在变量名前面加$)
Export 命令和选项
选项 |
值 |
-- |
|
-f |
|
-n |
|
-p |
|
格式:
1、 export 变量名=values
2、 变量名=values; expoer变量名
3、 Declare –x 变量名=value
提示:以上为三种设置环境变量的方法
例:
expoer NAME=oldboy
declare –x NAME=oldboy
NAME=oldboy;export NAME
自定义全局变量环境实例:
cat /etc/profile |grep OLD
export OLDBOY=’oldboy’
让配置生效
. ./etc/profile 后面echo $OLDBOY
显示系统环境变量
[root@mail2 aa]# env
取消环境变量
[root@mail2 aa]# unset USER
三、局部变量
定义本地变量在用户当前的shell生存期的脚本使用。例如,本地变量OLDBOY取值为ett098,这个值只在用户生成器中有意义。如果在shell中启动另一个进程或退出。本地变量OLDBOY值将无效。
普通字符串变量定义。
变量名=values 变量名=’values’ 变量名=”vaules”
例1
a=192.168.1.1 无引号 b=’192.168.1.1’ 单引号 c=”192.168.1.1” 双引号 echo $a echo $b echo $c
答案是:
a=192.168.1.1 b=192.168.1.1 c=192.168.1.1
例子2:
a=192.168.168.1.2-$a 无引号 b=’192.168.168.1.2-$a’ 单引号 c=”192.168.168.1.2-$a” 双引号 想想abc什么什么结果 a=192.168.168.1.2-192.168.1.1 b=192.168.1.2-$a c=192.168.168.1.2-192.168.1.1
为什么会这样呢。
提示:
第一种定义a变量的方式是直接定义变量内容,内容一般为简单连续的数字、字符串、路径
第二种定义b变量的方式是通过单引号定义变量、这个方式的特点是:输入变量时引号里面是什么就输入什么
第三种定义c变量方式是通过双引号定义变量、这个方式的特点是:输出变量时引号里的变量会经过解析后输入改变量内容。而不是把引号中的变量原样输出、适合字符串附带有变量的内容定义。
######shell 特殊变量
1、位置变量
$0 获取当前执行的shell脚本的文件名
$n 获取当前执行的shell脚本的第n个参数值、n=1….9 ,当n为0时表示脚本的文件名。如果n大于9,用大括号括起来${10}
$* 获取当前shell的所有参数、$1 $2 $3 …..注意与$#的区别
$# 获取当前shell命令行中参数的总个数
$@ 这个程序的所有参数 “$1” “$2” “$3” “$4”……..
2、进程状态变量
$$ 获取当前sehll的进程号(PID)
$! 执行上一个指令的PID
$? 获取执行的上一个指令的返回值(0为成功,非0为失败)####这个变量很常用
$_ 在此之前执行的命令或脚本的最后一个参数
#### 1.4 bash 内部变量
有些内部命令在忙目录列表时是看不见的。他们有shell本身提供,常用的内部命令有:echo、eval、exec、export、readonly、read、shift、exit和点(.)
echo 变量名表
将变量名表指定的变量显示到标准输出
eval args
读入参数args、并将他们组合成一个新的命令、然后执行、
exec 命令参数
当shell执行到exec语句时、不会去创建新的子进程、而是转去执行指定的命令、当指定的命令执行完是、该进程(也就是最初的shell)就会终止、所以shell程序中ecec后面的语句将不会贝执行
Expoer 变量名=value
Shell 可以用export把它的变量向下带入子shell、从而让子进程继承父进程中的环境变量、但子shell不能用expoer把它的变量向上带入父shell
Readonly 变量名
只读变量、用readonly显示所有只读变量
Read 变量名表
从标准输入字符串、传给指定变量、
可以在函数中用local变量名的方式申请局部变量
Shift语句
Shift语句按如下方式重新命名所有的位置参数变量、即$2成为$1,$3 成为$2 在程序中没使用一次shift语句、都使所有的位置参数一次向左移动一个位置、并使位置参数$#减一、直到减到0为止、
echo $1 $2 $3
if [ $2 -eq 2 ]
then
shift
echo $1
fi
执行一下
当$2等于2的时候用shift 就会向前变一位就是$1变为$2
#####变量子串常用操作
表达式 |
说明 |
${#string} |
返回$string的长度 |
${string:position} |
在$string中、从位置$position之后开始提取子串 |
${string:position:length} |
在$string中、从位置$position之后开始提取长度为$length子串 |
${string#substring} |
从变量$string开头开始删除最短匹配$substring子串 |
${string##substring} |
从变量$string开头开始删除最长匹配$substring子串 |
${string%substring} |
从变量$string开头开始删除最短匹配$substring子串 |
${string%%substring} |
从变量$string开头开始删除最长匹配$substring子串 |
${string/substring/replace} |
使用$replace,来代替第一个匹配的$substring |
${string/#substring/replace} |
使用$replace 前缀匹配$substring,使用$replace来代替匹配$substring |
${string/%substring/replace} |
使用$replace 后缀匹配$substring,使用$replace来代替匹配$substring |
例子定义一个变量
# OLDBOY=“ I am oldboy”
[root@mail2 sh]# echo ${OLDBOY}
i am oldboy
用第一个参数返回字符串的长度
[root@mail2 sh]# echo ${#OLDBOY} ####只要在变量前面加一个#号就行了
返回的结果是11 这个是没有错
现在使用第二个参数
[root@mail2 sh]# echo ${OLDBOY:2}
am oldboy
从第二个字符段开始截图
现在已经截取了从第二个字符串开始截取后面的字符串。
###测试第三个
[root@mail2 sh]# echo ${OLDBOY:2:2}
截取OLDBOY变量字符串从第二个字符开始截取、取两个字符
####测试第四个
[root@mail2 sh]# echo ${OLDBOY#i}
最短删除i这个字符
已经删除了i这个字符
提示:统一规律:#从开头开始、%从结尾开始的。
批量替换实例
把这个liang删除掉
运行一下脚本
#!/bin/sh
# jack ben facebook:1249648969@qq.com
for file in `ls ./*.jpg` ###定义file变量 变量的含义是查看本目录下的.jpg 所有文件
do ####开始fro循环
/bin/mv $file "${file%liang*}.jpg" #####mv 修改目录下的所有.jpg 文件从头开始删除liang包括后面的所有名称都删除
done ###结束语句
现在从新查看一下、已经成功了
在举例一个例子:
把HTM修改成小写的。
也可以用sed
echo $file|sed ‘s/HTM/htm/g’
如果脚本如下:
#!/bin/sh
for file in `ls ./*.HTML`
do
# mv $file `echo $file|sed 's/HTML/html/g'` ###这个sed 的修改方式
mv $file `echo "${file/%HTML/html}"` ###这是变量替换的方式
done
已经成功修改了后面的名字。
三、变量的数值计算
变量的数值计算常见的有如下几个命令
(()) 、let 、expr、bc 、$[]
1) (())用法:(此法很常用)
执行简单的整数运算,只需将特定的算术表达式用”$(( 和 ))” 括起来
[root@mail2 sh]# ((a=1+2**2-4%3))
[root@mail2 sh]# echo $a
8
或者 echo $((1+2**2-4%3))
[root@mail2 sh]# ((a=2**16))
[root@mail2 sh]# echo $a
65536
[root@mail2 sh]# echo $((a+=1)) ####就是表示a=a+1
65537
[root@mail2 sh]#
[root@mail2 sh]# echo $((a++))
1
[root@mail2 sh]# echo $a
2
[root@mail2 sh]#
a++ 的用法是先输入后面再执行操作
a --也是一样的先输出同样的数值,后面你在查看时会减少一位
也可以做加法运算
[root@mail2 sh]# echo $((100*(100+1)/2))
5050
公式是这样的 Nx(N+1)/2
#####
提示:
1、**为幂运算:%为取模运算就是除法当中的取余数)
2、上面涉及到的参数必须为整数(整形)。不能是小数点(符点数)或者字符串、bc命令可以进行浮点数运算、单一般较少用到、
3、echo $((a++)) 和echo $((a--)) 表示输出自身的值、然后在进行++的运算、echo$((++a))
和echo$((--a)) 表示先进行++ -- 的运算再输出本身的值
除法运算
[root@mail2 sh]# echo $(( 100 /5))
加法运算
[root@mail2 sh]# echo $(( 100 +5))
减法运算
[root@mail2 sh]# echo $(( 100 -5))
乘法运算
[root@mail2 sh]# echo $(( 100 *5))
平方计算
[root@mail2 sh]# echo $(( 100 **5))
取模法、余数
[root@mail2 sh]# echo $(( 100 %5))
#!/bin/sh
a=6
b=2
echo "a-b=$(($a-$b))"
echo "a+b=$(($a+$b))"
echo "a*b=$(($a*$b))"
echo "a/b=$(($a/$b))"
echo "a**b=$(($a**$b))"
echo "a%b=$(($a%$b))"
问题:如何把 a、b 两个变量通过命令行的传参的方式实现
解答
把a修改为=$1
把b修改为=$2
扩展:实现一个加、减、乘、除、等功能的计算器、通过命令行传参的方式实现
Let用法
格式:
Let赋值表达式
【注】let赋值表达式功能等同于:((赋值表达式))
#i=2
#i=i+8
提示:let i=i+8 等同于((i=i+8)) 后者效率更高
expr (evaluate exproressions ) 命令用法
expr 命令一般用于整数值、但也可用于字符串、用来求表达式变量的值、同时expr也是一个手工命令行的计算器、语法:expr Expression
[root@mail2 sh]# expr 2+2
2+2
[root@mail2 sh]# expr 2 + 2
4
[root@mail2 sh]# expr 2 * 2
expr: 语法错误
[root@mail2 sh]# expr 2 \* 2
4
[root@mail2 sh]# expr 2 % 2
0
[root@mail2 sh]# expr 10 % 2
0
[root@mail2 sh]#
提示:
1):注意运算符左右都有空格
2、使用乘号是、必须用反斜线屏蔽其特定含义、因为shell可能会误解星号的含义
可以用expr $[$a+$b]表达式形式、$a $b 可为整数
[root@mail2 ~]# expr $[2+2]
4
[root@mail2 ~]#
其他特殊的用法:
Expr用法 ssh-copy-id
if expr "$1" : ".*\.pub"; then’
bc 命令的用法
支持小数级的运算
echo 3.5+5|bc
[root@mail2 ~]# echo 37.8+56.8|bc
94.6
[root@mail2 ~]#
[root@mail2 ~]# echo "3.145*3.145"|bc
9.891
[root@mail2 ~]#
如何保留小数点的第一位呢?
[root@mail2 ~]# echo "scale=1;5.23/3.13"|bc
1.6
[root@mail2 ~]#
这个scale 只能使用于除法,不能使用与乘法
转换进制
[root@mail2 ~]# echo "obase=2;8"|bc ####10进制8转换成2进制
1000
[root@mail2 ~]# echo "obase=16;20"|bc #####10进制20转换为16进制
14
$[] 运算例子
[root@mail2 ~]# echo $[2+2]
Shell变量的输出
Shell变量除了可以直接赋值外、还可以使用read命令从标准输入获取
Read 语法格式
read [参数] [变量名]
常用参数:
-p prompt:设置提示信息
-t timeout 设置输入等待的时间、单位默认为秒
[root@mail2 ~]# read -t 5 -p "weloce input tow nuber:" a1 a2
weloce input tow nuber:
如果使用read的方式做一个加减乘除的方法
#!/bin/sh
read -t 5 -p "input two number" a b
echo "a-b=$(($a-$b))"
echo "a+b=$(($a+$b))"
echo "a*b=$(($a*$b))"
echo "a/b=$(($a/$b))"
echo "a**b=$(($a**$b))"
echo "a%b=$(($a%$b))"
利用read的方式写入$a $b
也可以使用这种方法
四、条件测试
条件测试语法
在bash的各种流程控制结构中通常需要进行各种测试、然后根据测试结果执行不同的操作、有时也会通过与if等条件语句相结合、使我们可以方便完成判断。
语法说明:
格式1:test<测试表达式>
格式2:[<测试表达式>]
格式3:[[<测试表达式>]]
说明:
格式1和格式2是等价的
格式3为扩展的test命令、有网友推荐用格式3、个人推荐格式2
提示:
1、 在[[]]中可以使用通配符进行模式匹配
2、 && 、||、>、< 、等操作符可以应用于[[]]中、单不恩能够应用于[]中
3、 对整数进行关系运算、也可以使用shell的算术运算符(())
语法例子:
格式1:test<测试表达式>
[root@mail2 sh]# test -f file && echo true||echo false
false
[root@mail2 sh]# touch file
[root@mail2 sh]# test -f file && echo true||echo false
true
测试这个file文件是否存在。如果存在输出true 如果不存在输出false
test 命令非(!)的写法 非的意思就是后面是真就为假。如果是假就是真
格式2 [<表达式>]
[root@mail2 sh]# [ -f file ] && echo 1||echo 0
0
[root@mail2 sh]# touch file
[root@mail2 sh]# [ -f file ] && echo 1||echo 0
1
如果加上非就是为0
格式3 [[<表达式>]]
4.2文件测试操作符
在书写测试表达式时、可以使用表中的文件测试操作符
常用文件测试操作符号 |
说明 |
-f 普通文件 |
若文件存在且为普通文件则为真 |
-d 文件目录 |
若文件存在且为目录则为真 |
-s 文件 |
若文件存在且不为空(文件大小非0)则真 |
-e 文件 |
若文件存在则为真 |
-r 文件 |
若文件存在且可读则真 |
-w 文件 |
若文件存在且可写则真 |
-x 文件 |
若文件存在且为链接文件则真 |
fl –nt f2 |
若文件f1比文件f2新则为真 |
fl –ot f2 |
若文件f1比文件旧则为真 |
-n |
长度不为0则为真 |
-z |
长度为0则真 |
字符串测试操作符
字符串测试操作符的作用:比较两个字符是否相同、字符串长度是否为零、字符串是否为null(注:bash区分零长度字符串和空字符串)
“=” 比较两个字符串是否相同,与==等价、如if[“$a” =”$b”],其中$a最好用、用“”括起来,因为如果中间有空格等就会出错、当然最好的方法就是if [“${a}”=”${b}”]。
“!=” 比较两个字符串是否相同、可以使用下面的表的字符串测试操作符
常用字符串测试操作符 |
说明 |
-z “字符串” |
若串长度为0则真 –z 可以理解为zero |
-n “字符串” |
若串长度不为0则真 –n 可以理解为no zero |
“串1”=“串2” |
若串1等于串2则真、可以用用==代替= |
“串1”!=“串2” 若串1不等于串2则真
注意说明:以上表格中字符串测试操作符号要用“”引起来
字符串测试操作提示:
1)-n 比较字符串长度是否不为零、如果不为零则为真如[-n “$myvar”]
2) –z 比较字符串长度是否为零、如果不为零则为真如 [-n “$myvar”]
整数二元比较操作符
在书写测试表达式时、可以时候能用下面的表中的整数二元比较操作符
在[]中使用的比较符号、 |
在(())和[[]]中使用的比较 |
说明 |
-eq |
== |
Equal缩写、相等 |
-ne |
!= |
Not equal的缩写、不相等 |
-gt |
> |
大于 great than |
-ge |
>= |
大于等于 great equal |
-lt |
< |
小于类似 less than |
-le |
<= |
小于等于 less equal |
提示:
1)“<” 符号意思是小于,if[[“$a”<”$b”]], if[“$a”\<”$b”]。在单[]中需要转义、因为shell也会<和>重定向
2)“>”符号意思是大于if[[“$a”>”$b”]], if[“$a”\>”$b”]。在单[]中需要转义、因为shell也会<和>重定向
3)”=” 符号意思是等于if[[“$a”=”$b”]], if[“$a”=”$b”]。在单[]中不需要转义
特别提示:
经过实践: = 和!= 在[]中不需要使用转义、包含< 、> 的符号在[]中使用需要转义、对于数字不转义的结果未必会报错、但是结果可能不对。
范例:二元数字比较
但是还是返回了1 说明这个是有问题的,尝试一下转义的情况
转义之后就是正确的了。说明在[] 中< > 是需要使用转义的。
也可以使用 lt 和gt 是使用方法
等号和不等号是不受影响的
范例2:二元字符比较
4.3逻辑操作符
在书写测试表达式时、可以使用如下表中的逻辑操作符实现复杂条件测试
在[]中使用的逻辑操作符 |
在[[]]中使用的逻辑操作符 |
说明 |
-a |
&& |
与,两端都为真、则真 |
-o |
|| |
或、两端有一个为真则真 |
! |
! |
非、相反则为真 |
提示:
!中文的意思是反:与一个逻辑值相反的逻辑值
-a 中文的意思是与(and &&) 两个逻辑值都为真,返回值为真、反之为假
-o 中文的意思是或(of ||)两个逻辑值只要有一个为真、返回值就为真
逻辑操作符运算规则
真1 假0 and符相当于乘法一样的
And 1*0=0 假
And 1*1=1 真
And 0*0=0 假
两端都是1才为真
Or 或 or相当于加法一样的
Or 1+0=1 真
Or 0+0=0 假
Or 0+1=1 真
条件测试举例
下面举一些条件测试的例子,为了清晰的显示测试结果、我们屏幕上输出1(表示真)或0(表示假)
提示:这和前面的状态变量:“$?”返回0为真不一样的。
1、以上两条语句功能相同的
2、变量$file 加了双引号、这是编程的好习惯、可以防止很多意外的错误发生、
文件测试举例
定义file1 和file2 两个变量,并分别赋予两个系统文件名的值
多条件文件测试:
可用 与(-a 和&&) 、或(-o 和 ||) 、非(!) 将表达式连接起来、接着上面的变量
注意:前面我们已经讲解过了。
1、 “-a”和 “-o” 逻辑操作符号用于[[]]中使用
2、 “&&”和“||”逻辑操作符号用于[[]]中使用
3、 注意括号两端、必须要有空格、
大 {} 的使用方法
单条件字符串测试
多条件字符串测试
[
root@mail2 sh]# [[ -z "$file1" && -z "$file2" ]] && echo 1
[root@mail2 sh]# [[ -z "$file1" || -z "$file2" ]] && echo 1
[root@mail2 sh]#
[root@mail2 sh]# [[ -z "$file1" || -z "$file2" ]] && echo 1 ||echo 0
0
[root@mail2 sh]# [[ -z "$file1" || -z "$file2" ]] && echo 1 ||echo 0
0
[root@mail2 sh]# [ "$file1" = "$file2" ] && echo 1 ||echo 0
0
[root@mail2 sh]# [ "$file1" != "$file2" ] && echo 1 ||echo 0
1
[root@mail2 sh]#
整数的二元比较
整数比较大小是否会通过字符串的大小对比吗?
测试
测试发现整数的比较是比较它的数字大小。而不是对比字符串的多少
逻辑操作符举例
#!/bin/sh
echo –n “请输入两个数字[格式为:m n]”;
read m n
###第一种写法
if [ ${m} –eq 1] && [ ${n} –eq 2 ];then
echo “good”
else
echo “bad”
fi
#####第二种写法
if [ ${m} –eq –a ${n} –eq 2 ];then
echo “good”
else
echo “bad”
fi
####第三种写法
if [[ ${m} –eq 1 && ${n} –eq 2 ]];then
echo “good”
else
echo “bad”
fi
&& 和-a 与逻辑符写法总结如下:
echo –n “请 输入两个字母或者任意单词[格式为 :a b]”;
read a b
###第一种写法
if [ “${a}” = “a” ] && [ “${b}” = “b” ];then
###第二种写法
if [ “${a}”= a –a “${b}” = “b” ];then
##第三种写法
if [[ “${a}” = “a” –a “${b}” =”b” ]];then
###下面写法不对
if (( “${a}” = “a” –a “${b}” =”b” ));then
echo “good”
else
echo “bad”
fi
需要把-a 改成 &&
范例2: || 和 –o或 逻辑符
[[ -z “$file1” || -z “$file2” ]] && echo 1 || echo 0
[ -z “$file1” -o -z “$file2” ] && echo 1 || echo 0
范例三:!非逻辑符
[ ! “$file1” = “$file2” ] && echo 1 || echo 0
单括号里面是对整个表达式的取反
[[ ! –z ”$file1” || !-n “$file2” ]] && echo 1 || echo 0
双括号里面只对 ||前面的一段取反、如果后面需要取反,需要加一个!(非)
EOF 明天更新吧。!!!睡觉去