shell俗称壳(用来区别于核),提供使用者使用界面(命令解析器),它接受用户命令,然后调用相应的应用程序。
同时它还是一种程序设计语言,作为命令语言,它交互式解释和执行用户输入的命令或者自动地解释和执行预先设计好的一连串的命令。作为程序涉及语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。
一、shell脚本基础概念
shell的编程风格是过程式,即以指令为中心,数据服务指令。
shell程序提供了编程能力,解释执行。
shell编程语言的基本结构
数据存储:变量、数组
表达式:a+b
语句:if
shell编程逻辑处理方式
顺序执行
循环执行
选择执行
shell脚本是包含一些命令或声明,并符合一定格式的文本文件
格式要求:首行shebang机制
#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl
shell脚本的用途
自动化常用命令
执行系统管理和故障排除
创建简单的应用程序
处理文本或文件
创建shell脚本
第一步:使用文本编辑器来创建文本文件
第一行必须包括shell声明序列:#!
#!/bin/bash
添加注释
注释以#开头
第二步:运行脚本
给予执行权限,chmod +x file.sh 在命令行上指定脚本的绝对或相对路径
直接运行解释器,将脚本作为解释器程序的参数运行
脚本调试
bash -n /wang/jiaoben.sh
检查脚本中的语法错误
bash -x /wang/jiaoben.sh
调试执行
[root@localhost wang]# bash -x jiaoben1.sh + wang=100 + echo 100 100 ++ 200 jiaoben1.sh: line 5: 200: command not found + laowang= + echo '' 注:一边执行,一边检查语法:jiaoben1.sh第五行 200这个命令找不到
二、变量
命名的内存空间
数据存储方式
字符:
数值:整型,浮点型
变量类型
作用
数据存储格式
参与的运算
表示的数据范围
类型
字符
数值:整型,浮点型
强类型:定义变量时必须指定类型,参与运算必须符合类型要求,调用未声明变量会产生错误
例:java,python
弱类型:无须指定类型,默认均为字符型,参与运算会自动进行隐式类型转换,变量无须事先定义可直接调用
例:bash 不支持浮点数
变量命名法则:
不能使用程序中的保留字,例:if,for
只能使用数字、字母及下划线,且不能以数字开头
见明知亿
统一命名规则:驼峰命名发,例:大驼峰SumFile,小驼峰sumFile
bash中变量的种类
根据变量的生效范围等标准
本地变量:生效范围为当前shell进程,对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效。
环境变量:生效范围为当前shell进程及其子进程
局部变量:生效范围为当前shell进程中某代码片段(通常指函数)
位置变量:$1,$2…来表示,用于让脚本在脚本代码中调用通过命令行传递给它的参数
特殊变量:$?,$0,$*,$@,$#
本地变量
变量赋值:name=‘函数(value)’
可以使用引用value:
可以是直接字符串:name=“root”
变量引用:name=“$USER”
命令引用:name=`command`或name=$(command)
变量引用:${name},$name
"":弱引用,其中的变量引用会被替换为变量值
'':强引用,其中的变量引用不会被替换为变量值,而保持原字符串
显示已定义的所有变量:set
删除变量:unset name
本地变量不可给子shell进程使用。
[root@localhost wang]# cat jiaoben1.sh #!/bin/bash wang=100 echo $wang [root@localhost wang]# bash jiaoben1.sh 100 [root@localhost wang]# echo $wang [root@localhost wang]#
环境变量
变量声明、赋值
export name=value
declare -x name=value
变量引用:${name},$name
显示所有环境变量
export
env
printenv
删除环境变量
unset name
环境变量可以在当前shell生效,exit退出就不会生效,可以给子进程使用
bash有许多内建的环境变量:PATH,SHELL,USER,UID,HISTSIZE,HOME,PWD,OLDPWD,HOSTFILE,PS1
[root@localhost wang]# export wang=100 [root@localhost wang]# cat jiaoben1.sh #!/bin/bash echo $wang [root@localhost wang]# bash jiaoben1.sh 100
只读变量
只能声时,但不能修改和删除
readonly name
declare -r name
定义之后永久保存在缓存中,exit退出即可取消定义
[root@localhost wang]# readonly wang=1 [root@localhost wang]# echo $wang 1 [root@localhost wang]# wang=2 -bash: wang: readonly variable [root@localhost wang]# wang=1 -bash: wang: readonly variable
位置变量
在脚本代码中调用通过命令行传递给脚本的参数
$1,$2…:对应第1,第2等参数,shift[n]换位置
$0:命令本身
$*:传递给脚本的所有参数,全部参数合为一个字符串
$@:传递给脚本的所有参数,每个参数为独立字符串
$#:传递给脚本的参数的个数
$@,$*只在被双引号包起来的时候才会有差异
[root@localhost wang]# cat jiaoben1.sh #!/bin/bash echo "第一个参数是$1" echo "第二个参数是$2" echo "第三个参数是$3" echo "所有参数是$*" echo "所有参数是$@" echo "参数的个数是$#" [root@localhost wang]# bash jiaoben1.sh aaa bbb ccc 第一个参数是aaa 第二个参数是bbb 第三个参数是ccc 所有参数是aaa bbb ccc 所有参数是aaa bbb ccc 参数的个数是3 [root@localhost wang]# cat jiaoben1.sh #!/bin/bash maxuid=`cat $1 | cut -d: -f3 |sort -nr | head -n1` echo "$maxuid" [root@localhost wang]# bash jiaoben1.sh /etc/passwd 1000
三、算术运算
bash中的算术运算:help let
+,-,*,/,%(取余),**(乘方)
实现算术运算
let var=算术表达式
var=$[算术表达式]
var=$((算术表达式))
var=$(expr arg1 arg2 arg3…)
echo '算术表达式' |bc
declare -i var=数值
乘法符号有些场景中需要转义。例:*
bash有内建的随机数生成器:$RANDOM(0-32767)
[root@localhost ~]# let wang=2*3 [root@localhost ~]# echo $wang 6 [root@localhost ~]# wang=$[3*4] [root@localhost ~]# echo $wang 12 [root@localhost ~]# wang=$((1+3+4)) [root@localhost ~]# echo $wang 8 [root@localhost ~]# echo "3*(5+6)"|bc 33 [root@localhost ~]# echo $[RANDOM%10] 1 [root@localhost ~]# echo $[RANDOM%10] 6 [root@localhost ~]# echo $[RANDOM%10] 5
四、逻辑运算
true:1 false:0
与:
1与1=1
1与0=0
0与1=0
0与0=0
或
1或1=1
1或0=1
0或1=1
0或0=0
非:
!
!1=0
!0=1
短路运算
短路与
第一个为0,结果必定为0
第一个为1,第二个必须要参与运算
command1 command2
command1成功,执行command2
command1失败,不执行command2
短路或||
第一个为1,结果必定为1
第二个为0,第二个必须要参加运算
command1 command2
command1成功,不执行command2
command1失败,执行command2
异或:^
异或的两个值,相同为假,不同为真
五、聚集命令
有两种聚集命令的方法
复合式:date; who|wc -l
命令会一个接一个的运行
子shell:(date; who|ec -l)>>/tmp/trace
所有的输出都被发送给单个输出和输入
[root@localhost sh.log]# date;hostname;who Thu Aug 11 19:49:53 CST 2016 localhost.localdomain root tty1 2016-08-09 17:41 root pts/0 2016-08-11 18:53 (192.168.1.106) root pts/3 2016-08-11 14:06 (192.168.1.106) [root@localhost sh.log]# date;hostname;who|wc -l Thu Aug 11 19:50:08 CST 2016 localhost.localdomain 3 [root@localhost sh.log]# (date;hostname;who)|wc -l 5 [root@localhost sh.log]# (date;hostname;who)|wc -l
六、退出状态
进程使用退出状态来报告成功或失败
0 代表成功,1-255代表失败
$?变量保存最近的命令退出状态
[root@localhost sh.log]# ping -c1 -W1 192.168.1.1 &> /dev/null [root@localhost sh.log]# echo $? 0 [root@localhost sh.log]# ping -c1 -W1 192.168.1.256 &> /dev/null [root@localhost sh.log]# echo $? 2 [root@localhost sh.log]# useradd wang [root@localhost sh.log]# grep -q "laowang" /etc/passwd [root@localhost sh.log]# echo $? 1 [root@localhost sh.log]# grep -q "wang" /etc/passwd [root@localhost sh.log]# echo $? 0
退出状态码
bash自定义退出状态码
exit[n]:自定义退出状态码
注:脚本中一旦遇到exit命令,脚本会立即终止,终止退出状态取决与exit命令后面的数字
注:如果未给脚本制定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码
七、条件测试
判断某需求是否满足,需要由测试机制来实现
专用的测试表达式需要由测试命令辅助完成测试过程
评估布尔声明,以便用在条件性执行中
若真,则返回0
若假,则返回1
测试命令
test expression
[ expression ]
[[ expression ]]
注:expression前后必须有空白字符
条件性的执行操作符
根据退出状态而定,命令可以有条件地运行
&&代表条件性的and then
||代表条件性的or else
[root@localhost sh.log]# ping -c1 -W1 192.168.1.1 &> /dev/null && echo "能ping通" || echo “不能ping通” 能ping通 [root@localhost sh.log]# ping -c1 -W1 192.168.1.256 &> /dev/null && echo "能ping通" || echo "不能ping通" 不能ping通
bash测试类型
数值测试
-gt:是否大于
-ge:是否大于等于
-eq:是否不等于
-ne:是否小于
-le:是否小于等于
字符串测试
==:是否等于
>:ascii码是否大于ascii码
<:是否小于
!=:是否不等于
=~:左侧字符串是否能够被右侧的pattern所匹配
注:此表达式一半用于[[]]中
-z‘string’:字符串是否为空,空为真,不空为假
-n‘string’:字符串是否不空,不空为真,空为假
注:用于字符比较时的用到的操作数都应该使用引号
[root@localhost wang]# cat jiaoben1.sh #!/bin/bash maxdisk=`df|grep "^tmpfs"|tr -s " " "%" |cut -d% -f5|sort -nr|head -n1` maxshiyonglv=80 [ $maxdisk == $maxshiyonglv ] && echo "磁盘空间要爆满" || echo "磁盘空间没爆满" [root@localhost wang]# bash jiaoben1.sh 磁盘空间没爆满 [root@localhost wang]# cat jiaoben2.sh #!/bin/bash maxdisk=`df|grep "^tmpfs"|tr -s " " "%" |cut -d% -f5|sort -nr|head -n1` maxshiyonglv=80 [ $maxdisk -gt $maxshiyonglv ] && echo "磁盘空间要爆满" || echo "磁盘空间没爆满" [root@localhost wang]# bash jiaoben2.sh 磁盘空间没爆满
文件测试
存在性测试
-a file:同-e
-e file:文件存在性测试,存在为真,否则为假
存在性及类别测试
-b file:是否存在且为块设备文件
-c file:是否存在且为字符设备文件
-d file:是否存在且为目录文件
-f file:是否存在且为普通文件
-z file:文件是否存在
-h file 或-L file :存在且为符号链接文件
-p file:是否存在且为命名管道文件
-S file:是否存在且为套接字文件
文件权限测试
-r file:是否存在且可读
-w file:是否存在且可写
-x file:是否存在且可执行
文件特殊权限测试
-g file:是否存在且拥有sgid权限
-u file:是否存在且拥有suid权限
-k file:是否存在且拥有sticky权限
文件大小测试
-s file:是否存在且非空
文件是否打开
-t fd:fd表示文件描述符是否已经打开且与某终端相关
-N file:文件自动上一次被读取之后是否被修改过
-O file:当前有效用户是否为文件属主
-G file:当前有效用户是否为文件属组
双目测试
file1 -ef file2:file1与file2是否指向同一个设备上的相同inode
file1 -nt file2:file1是否新于file2
file1 -ot file2:file1是否旧于file2
组合测试条件
第一种方式
command1 && aommand2 并且
command1 || aommand2 或者
!command 非
如:[ -e file ] && [ -r file ]
第二种方式
expression1 -a expression2 并且
expression1 -o rxpression2 或者
!expression
必须使用测试命令进行
[wang@www wang]$ ll total 16 ----------. 1 root root 0 Aug 11 23:36 file1 -rwxrwxrwx. 1 root root 16 Aug 11 11:21 file2 drwxr-xr-x. 2 root root 4096 Aug 11 10:11 jiaoben -rwxr-xr-x. 1 root root 111 Aug 12 00:30 jiaoben1.sh -rw-r--r--. 1 root root 110 Aug 11 23:28 jiaoben2.sh [wang@www wang]$ cat jiaoben1.sh #!/bin/bash [ -r $1 -o -x $1 ] && echo "该文件有读或写权限" || echo "该文件没有读或写权限" [wang@www wang]$ bash jiaoben1.sh file1 该文件没有读或写权限 [wang@www wang]$ bash jiaoben1.sh file2 该文件有读或写权限 [wang@www wang]$ cat jiaoben2.sh #!/bin/bash [ -r $1 -a -x $1 ] && echo "这个文件有读写权限" ||echo "这个文件没有读写权限" [wang@www wang]$ bash jiaoben2.sh file1 这个文件没有读写权限 [wang@www wang]$ bash jiaoben2.sh file2 这个文件有读写权限
使用read来输入值分配给一个或多个shell变量
-p 指定要显示的提示
-t timeout
read 从标准输入中读取值,给每个单词分配一个变量
所有剩余单词都被分配给最后一个变量
read -p “Enter a filename:” FILE
[root@www wang]# cat jiaoben1.sh #!/bin/bash read -p "input a number:" [root@www wang]# bash jiaoben1.sh input a number:laowang
流程控制
过程是编程语言
顺序执行
选择执行
循环执行
原创文章,作者:DYW,如若转载,请注明出处:http://www.178linux.com/34064