本章学习内容
----------什么是shell
----------shell类型
----------shell分类
----------shell脚本的特点
----------shell脚本的语法格式
----------shell脚本的语法基础
一、什么是shell
shell既是一个可执行程序,又是一种程序设计语言。作为执行程序,它交互式地解释和执行用户输入的命令,是用户和Unix/Linux沟通的桥梁;作为程序设计语言,它可以定义变量和参数,在一定程度具备编程的能力。虽然不属于系统内核的一部分,但它调用了系统核心的大部分功能来执行程序、建立文件并以并行的方式协调各个程序的运行。因此,对于用户来说,shell是最重要的实用程序。
二、shell类型
bsh,csh,zsh..众多的shell类型功用和bash大同小异,只不过语法格式有时略有不同。
三、shell脚本在编程程序语言中的分类
<1>面向过程和面向对象分类
bash是面向过程式编程语言
过程式:以指令为中心来组织代码,数据服务于代码
对象式:以数据为中心,指令服务与数据
<2>编译型语言和解释性语言分类
bash是解释型语言
解释执行,并不像java、c那样生成.class文件再进行编译
<3>弱类型和强类型语言分类
bash是弱类型语言
◆bash是弱类型语言相对于强类型语言带来三个改变
<1>变量无需声明
<2>声明和赋值可同时进行
<3>变量需要使用$引用
从下面几个方面对比弱类型语言和强类型语言的优缺点
对于字符串赋值而言,因为bash中变量无需声明,所以直接赋值即可,c则需要声明。bash胜
对于数值计算而言,都需要赋值,只不过bash可以赋值声明和赋值可同时进行。bash略胜
示例
int a intb int c c=a+b print c # C语言格式 declare -i c declare -i a declare -i b c=a+b echo $c 或者 c=$[a+b] 或者 c=$[$a+$b] # bash格式
写为c=$[$a+$b] 是为了不与其他字符串变量引用混淆。变量引用这是弱类型语言的弱点,而且bash这个弱类型编程语言的计算能力很差。
bash中默认类型是字符
root@centos7 /tmp]#a=1 [root@centos7 /tmp]#b=2 [root@centos7 /tmp]#c=$a+$b [root@centos7 /tmp]#echo $c 1+2 [root@centos7 /tmp]#declare -i a=1 [root@centos7 /tmp]#declare -i b=2 [root@centos7 /tmp]#c=$a+$b [root@centos7 /tmp]#echo $c 1+2 [root@centos7 /tmp]#declare -i c [root@centos7 /tmp]#c=$a+$b [root@centos7 /tmp]#echo $c 3 # c不转换数值型,无法识别1+2
四、shell脚本的特点及应用
<1>特点:虽然shell编程不像Java那样强大,但是它们能够轻易的处理文件目录之类的对象,例如:打印一个字符串只需要一个echo即可,而不需要像java那样需要定义类和对象之类的框架结构。这也正弥补了解释型语言在速度上的缺陷。
<2>shell脚本的用途有:
自动化常用命令
执行系统管理和故障排除
创建简单的应用程序
处理文本或文件
五、shell脚本的执行条件和语法格式
1、执行条件:
<1>作为可执行程序运行(给予执行权限,在命令行上指定脚本的执行路径)
注:任何一个可执行程序,如果要执行,必须在PATH环境变量中,以保证根可以找到程序,否则无法执行
<2>作为指定特定解释器的参数运行
2、语法格式
第一行必须声明默解释环境(Shabang机制):#!/bin/bash,那么它执行时会默认用当前Shell去解释这个脚本(即:$SHELL环境变量)
语法格式1 if语句
if ..; then
...
[elif
...]
[elif
...]
[else (保底条件)
...]
fi
语法格式2 case语句 适合离散输入的判断
case 变量引用 in
PATH1)
分支1
;;
PATH)
分支2
;;
*) (保底条件)
默认分支
;;
esac
case支持glob风格的通配符:
*: 任意长度任意字符
?: 任意单个字符
[]:指定范围内的任意单个字符
a|b: a或b
语法格式3 for语句
for 变量名 in 变量列表; do 也可用于循环,数组
循环体
done
注意:while语句完全替代for语句。当然,也仅限于像数字这样的递增数列时,如果是列出某文件列表的话,还是使用for语句。for的c语言格式也可以用于循环。
语法格式4 while语句
while 判断条件; do
循环体
done
语法格式5 until语句
until 判断条件; do
循环体
done
注意:while和until要提前定义变量,for中在列表中以定义
语法格式6 区分continue、break和exit
<1>continue:退出本次循环
<2>break:退出本轮循环
<3>exit:退出shell
#!/bin/bash # for i in {1..3}; do for j in {1..10}; do [ $j -eq 7 ] && continue # 当j=7时,退出本次循环,所以输出三次1-10,但是没有7 echo $j done
#!/bin/bash # for i in {1..3}; do for j in {1..10}; do [ $j -eq 7 ] && break # 当j=7时,退出第二个for循环,所以输出三次1-6 echo $j 此处的break可以换做cotinue 2 done done
#!/bin/bash # for i in {1..3}; do for j in {1..10}; do [ $j -eq 7 ] && exit # 当j=7时,退出bash脚本,所以只是输出了1-6六个数字 echo $j 此处的exit也可以换做break 2 done done
语法格式7:shift
shift会跳过指定数量的位置变量
#!/bin/bash # echo "1st arg is $1" echo "all arg is $@" shift echo "1st arg is $1" echo "all arg is $@" shift echo "1st arg is $1" echo "all arg is $@" shift 2 # 跳过2个位置变量 echo "1st arg is $1" echo "all arg is $@" [root@centos7/tmp]#bash shift.sh 1 2 3 4 5 6 1st arg is 1 all arg is 1 2 3 4 5 6 1st arg is 2 all arg is 2 3 4 5 6 1st arg is 3 all arg is 3 4 5 6 1st arg is 5 # 跳过3和4,直接输出5 all arg is 5 6
bash中传递参数的俩种方式
脚本参数 (位置参数)
read
语法格式8:read读入的变量不可以当作位置变量使用
[root@localhost ~]#vim testread.sh #!/bin/bash read -p "please input:" VAR if [[ $1 == 1 ]]; then echo ok fi [root@localhost ~]#bash -x testread.sh + read -p 'please input:' VAR please input:1 + [[ '' == 1 ]] ######$1显示为空,证明
脚本的退出状态码
默认取决于脚本中执行的最后一个语句
exit定义
函数的退出状态码
默认取决于函数中执行的最后一条语句
return定义
六、shell脚本中的语法基础
变量
这里当然不是说字符串、整型什么的,其实 bash 中的变量都可以理解为字符串。bash 中有四种类型的变量,它们是环境变量、本地变量、位置变量和特殊变量。
本地变量
环境变量 PATH PWD HOSTNAME HISTORY
定义方法:export VALUE
declare -x VALUE
局部变量
位置变量 $1,$2
特殊变量 $# $* $@ $? $0
运算
算术运算
let a=b+c
let a+=1
echo $a
a=$[$a+$b]
echo $a
a=`expr 2 + 3`
echo $a
逻辑运算
&& || !取反
注意:如果多条命令出现在逻辑关系中,建议加小括号
条件测试
字符串测试
=~ :一般使用[[ ]]匹配模式,globbing或者正则表达式或者扩展的正则表达式
#!/bin/bash
#
read -p "input a num: " n
[ -z $n ] && echo "at least one parameter"
[[ $n =~ ^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$ ]] && (echo "ok ip"; ping $n &> /dev/null && echo "ok access" || echo "no access") || echo "no ok ip"
==
>
<
!= :以上比较的都是字符串对应的ASCII码的大小
-z : 字符串是否为空,空为真
-n :
数值测试
-eq
-ne
-gt
-ge
-lt
-le
文件测试
-e:文件是否存在
-f:是否存在且为普通文件
-s:文件是否不为空
注意,测试要加[ ]
组合测试
-a -o -!
[ ! -r /tmp/file1 -a ! -w /tmp/file1 ]
注意:对于字符串测试和数值测试同样适用于此种格式
1、如果要使用globbing或者正则表达式或者扩展的正则表达式要使用[[ ]],一般使用在字符串的~=中。
2、找不到错误时可以更换[]或者[[]]
注意 :组合测试中的-a ,-o,!一般用在测试条件间的逻辑,而逻辑运算中的&&,|| 一般用在命令执行结果中的判断
注意:命令间的或是短路或的意思,条件间的或是普通或的意思
命令引用
$() ``
变量替换
$VALUE
[root@centos7 ~]#a=1 [root@centos7 ~]#b=2 [root@centos7 ~]#ab=3 [root@centos7 ~]#echo $ab 3 [root@centos7 ~]#echo ${a}b 1b [root@centos7 ~]#
七、数组
数组也适用于文件
[root@centos7~/bin]#file=`ls /root` [root@centos7~/bin]#echo ${file[*]}
1、 数组:变量的集合,可通过数字来索引到特定的变量
2、定义数组
<1>声明数组
declare -a array:声明普通数组
declare -A array:声明关联数组,必须声明
[root@centos7~]#unset aa #删除数组 #unset aa[#]:删除数组中某个元素 [root@centos7~]#declare -A aa [root@centos7~]#aa=([a]=1 [b]=2 [c]=3) [root@centos7~]#echo ${aa[a]} 1
<2>定义数组
aa[0]=1:定义单个数组元素
aa=(1 2 3):定义多个数组元素
aa=([0]=0 [2]=2]):不规则定义数组元素
3、引用数组
引用数组的元素
${aa}:引用变量aa的值
${aa}:列出第一个元素
${aa[0]}: 列出第一个元素
${#aa[0]}: 引用第一个元素的长度
${aa[*]}: 列出所有元素
${aa[@]}: 列出所有元素
${#aa[@]}:列出所有元素的个数
八、字符串处理
<1>切片
格式:${var:offset:number}
offset:跳过的字符个数
number:取得的的字符长度
[root@centos7~]#bb=xix:x:4369:4369::/home/xix:/bin/bash [root@centos7~]#echo ${bb} xix:x:4369:4369::/home/xix:/bin/bash [root@centos7~]#echo ${bb:3:5} :x:43 [root@centos7~]#echo ${bb: -3} # 中间必须又空格,取后三个字符 ash [root@centos7~]#echo ${bb:5:-3} # 去掉前5个字符和后3个字符 :4369:4369::/home/xix:/bin/b
<2>基于模式取子串
#:自左向右
@:自右向左
[root@centos7~]#cc=/var/log/messages [root@centos7~]#echo ${cc#*/} # 自左向右删除第一个/之前的内容,包括斜线 var/log/messages [root@centos7~]#echo ${cc##*/} # 自左向右删除所有/之前的内容,包括斜线 messages
[root@centos7~]#dd=http://www.magedu.com:80 [root@centos7~]#echo ${dd%:*} # 自右向左删除第一个:之后的内容,包括: http://www.magedu.com [root@centos7~]#echo ${dd%%:*} # 自右向左删除所有:之后的内容,包括: http
<3>查找替换
/:第一次匹配到的
//:所有被匹配到的
#:行首被匹配到的
%:行尾被匹配到的
[root@centos7~]#ee=bash:x:0:0::/root:/bin/bash [root@centos7~]#echo ${ee/root/zhao} # 只需要俩个/ zhao:x:0:0::/root:/bin/bash [root@centos7~]#echo ${ee//root/zhao} zhao:x:0:0::/zhao:/bin/bash [root@centos7~]#echo ${ee/#bash/zhao} zhao:x:0:0::/root:/bin/bash # 该变行首 [root@centos7~]#echo ${ee/%bash/zhao} bash:x:0:0::/root:/bin/zhao # 改变行尾 [root@centos7~]#
<4>查找并删除
/: 第一个
//:行首
/#:行首
/%:行尾
[root@centos7~]#ff=root:x:0:0::/root:/bin/bash [root@centos7~]#echo ${ff/r..t} root:x:0:0::/root:/bin/bash # 不支持正则表达式 [root@centos7~]#echo ${ff/r??t} # 支持通配符 :x:0:0::/root:/bin/bash [root@centos7~]#echo ${ff/r*t} :/bin/bash [root@centos7~]#echo ${ff//r??t} :x:0:0::/:/bin/bash [root@centos7~]#echo ${ff/#root} :x:0:0::/root:/bin/bash # 取子串也可以做到
<5>字符大小写转换
^^: 所有小写转换大写
..:所有大写转换小写
[root@centos7~]#gg=ggggggg [root@centos7~]#echo ${gg^^} # 转换大写 GGGGGGG [root@centos7~]#hh=`echo ${gg/#root}` [root@centos7~]#echo ${hh,,} # 转换小写 ggggggg
九、变量赋值
1、${var:-value}:如果var为空或未设置,那么返回value;否则,则返回var的值
[root@centos7~]#var=prompt [root@centos7~]#echo ${var:-tidle} prompt
2、${var:+value}:如果var不空,则返回value
[root@centos7~]#var=prompt [root@centos7~]#echo ${var:+tidle} tidle
3、${var:=value}:如果var为空或未设置,那么返回value,并将value赋值给var;否则,则返回var的值
[root@centos7~]#unset var [root@centos7~]#echo ${var:=tidle} tidle [root@centos7~]#echo $var tidle
4、${var:?error_info}:如果var为空或未设置,那么返回error_info;否则,则返回var的值
[root@centos7~]#unset var [root@centos7~]#echo ${var:?error} -bash: var: error
如果脚本中变量较多时,要为脚本中的变量设置配置文件,source该文件即可
十、间接变量引用
描述:变量中存在的是另一个变量,而真正的值存在于另一个变量中
1、引用方法
<1>${!var}
<2>\$$var
[root@centos7~]#shortname=hh [root@centos7~]#longname=haha [root@centos7~]#name=shortname [root@centos7~]#echo ${!name} hh [root@centos7~]#eval right=\$$name # 必须借助right这个变量 [root@centos7~]#echo $right hh
十一、调用shell脚本模版
<1>编辑/root/.vimrc
[root@centos7~]#vim .vimrc autocmd BufNewFile *.sh 0r ~/.vim/example.sh # 添加次行
<>编辑/root/.vim/example.sh
[root@centos7~]#vim .vim/example.sh #!/bin/bash # 添加这四行,创建脚本时会自动读入 #Author:Zhao #Name: #Function: