bash脚本编程
脚本文件格式:
第一行,顶格写: #!/bin/bash
注释行:#开头
代码注释:写清楚注释
规范写脚本:适度缩进,添加空白行
编程语言:有编程语法格式,库,算法和数据结构
编程思想:
用代码解决问题空间-->用编程语言来解空间
变量的类型:
局部变量
本地变量
环境变量
位置参数变量
特殊变量
数据类型:字符型、数值型
shell属于弱类型,本身不支持浮点数,可借助其它工具来实现;是字符型
算术运算的表达方式:
+,-,*,/,%,**
let VAR=$num1 operator $num2
VAR=$[expression]
VAR=$((expression))
VAR=$(expr argu1 argu2 argu3)
注意:有些时候乘法符号需要转义
增强型赋值:
变量做某种算术运算后回存至此变量中:
let i=$i+#
let i+=#
+=,-=,*=,/=,%=
自增:
VAR=$[$VAR+1]
let VAR+=1
let VAR++
自减:
VAR=$[$VAR-1]
let VAR-=1
let VAR--
练习:
1、写一个脚本,内容是:计算/etc/passwd文件中的第10个用户和第20个用户的id号之和
#!/bin/bash
#
id1=$(head -10 /etc/passwd | tail -1 | cut -d: -f3)
id2=$(head -20 /etc/passwd | tail -1 | cut -d: -f3)
echo "The id1: ${id1}"
echo "The id2: ${id2}"
id_sum=$[${id1}+${id2}]
echo "The id_sum: ${id_sum}"
2、写一个脚本,内容是:计算 /etc/rc.d/init.d/functions 和 /etc/inittab 文件的空白行数之和
#!/bin/bash
#
k1=$(grep "^[[:space:]]*$" /etc/rc.d/init.d/functions | wc -l)
k2=$(grep "^[[:space:]]*$" /etc/inittab | wc -l)
sum=$[$k1+$k2]
echo "File k1: $k1"
echo "File k2: $k2"
echo "Sum: $sum"
3、写一个脚本计算两个用户user1,user2的id之和
~]# cd /tmp/
~]# mkdir scripts
~]# cd scripts/
~]# vim sum.sh
#!/bin/bash
#
id user1 &> /dev/null || useradd user1
ip user2 &> /dev/null || useradd user2
user1_id=$(id -u user1)
user2_id=$(id -u user2)
echo "The user1 id: ${user1_id}"
echo "The user2 id: ${user2_id}"
id_sum=$[$user1_id+$user2_id]
echo "The id sum: $id_sum."
条件测试:
判断某需求是否满足,需要由测试机制来实现
如何编写测试表达式以实现所需的测试:
(1)执行命令,并利用命令状态返回值来判断
例:]# grep "^$" /etc/rc.d/init.d/functions &> /dev/null
]# echo $?
0
例:]# who | grep "^centos>"
]# echo $?
1
0:成功
1-255:失败
(2)测试表达式
test EXPRESSION
[ EXPRESSION ]
[[ EXPRESSION ]]
注意:EXPRESSION两端必须有空白字符,否则为语法错误
bash的测试类型:
数值测试
字符串测试
文件测试
数值测试:数值比较
-eq 等于,如:if [ "$a" -eq "$b" ]
-ne 不等于,如:if [ "$a" -ne "$b" ]
-gt 大于,如:if [ "$a" -gt "$b" ]
-ge 大于等于,如:if [ "$a" -ge "$b" ]
-lt 小于,如:if [ "$a" -lt "$b" ]
-le 小于等于,如:if [ "$a" -le "$b" ]
< 小于(需要双括号),如:(("$a" < "$b"))
<= 小于等于(需要双括号),如:(("$a" <= "$b"))
> 大于(需要双括号),如:(("$a" > "$b"))
>= 大于等于(需要双括号),如:(("$a" >= "$b"))
字符串测试:
= 等于,如:if [ "$a" = "$b" ]
== 等于,如:if [ "$a" == "$b" ],与=等价
注意:==的功能在[[]]和[]中的行为是不同的,如下:
1 [[ $a == z* ]] # 如果$a 以"z"开头(模式匹配)那么将为 true
2 [[ $a == "z*" ]] # 如果$a 等于 z*(字符匹配),那么结果为 true
3
4 [ $a == z* ] # File globbing 和 word splitting 将会发生
5 [ "$a" == "z*" ] # 如果$a 等于 z*(字符匹配),那么结果为 true
一点解释,关于 File globbing 是一种关于文件的速记法,比如"*.c"就是,再如~也是.
但是 file globbing 并不是严格的正则表达式,虽然绝大多数情况下结构比较像.
!= 不等于,如:if [ "$a" != "$b" ]
这个操作符将在[[]]结构中使用模式匹配.
< 小于,在 ASCII 字母顺序下.如:
if [[ "$a" < "$b" ]]
if [ "$a" < "$b" ]
注意:在[]结构中"<"需要被转义.
> 大于,在 ASCII 字母顺序下.如:
if [[ "$a" > "$b" ]]
if [ "$a" > "$b" ]
注意:在[]结构中">"需要被转义.
具体参考 Example 26-11 来查看这个操作符应用的例子.
-z 字符串为"null".就是长度为 0.
-n 字符串不为"null"
注意:
使用-n 在[]结构中测试必须要用""把变量引起来.使用一个未被""的字符串来使用! -z
或者就是未用""引用的字符串本身,放到[]结构中
==:是否等于
>:是否大于
<:是否小于
!=:是否不等于
=~:左侧字符串是否能够被右侧的PATTERN所匹配
例: ]# name=tom
]# [[ "$name" =~ o.* ]]
]# echo $?
-z "STRING":判断指定的字符串是否为空;空则为真,不空则为假
-n "STRING":判断指定的字符串是否为不空;不空则为真,空则为假
注意:
(1)变量字符串要加引号;不做变量替换就加单引号,做变量替换就加双引号
(2)做字符比较时要使用[[]]
脚本的状态返回值:
默认是脚本中执行的最后一条命令的状态返回值;
我们可以自定义状态退出状态:
exit [n]:n为自己指定的状态码
注意:shell进程遇到exit时,即会终止,因此,整个脚本执行即为结束
文件测试
-a FILE 这个选项的效果与-e 相同.但是它已经被弃用了,并且不鼓励使用
-e FILE
文件的存在性测试,存在则为真,否则为假
存在性及类型测试
-b FILE:是否存在并且为 块设备 文件
-c FILE:是否存在并且为 字符设备 文件
-d FILE:是否存在并且为 目录 文件
-f FILE:是否存在并且为 普通 文件
-h FILE 或 -L FILE:是否存在并且为 符号连接 文件
-p FILE:是否存在并且为 命名管道 文件
-S FILE:是否存在并且为 套接字 文件
文件权限测试:
-r FILE:是否存在并且对当前用户 可读
-w FILE:是否存在并且对当前用户 可写
-x FILE:是否存在并且对当前用户 可执行
特殊权限测试:
-u FILE:是否存在并且 拥有suid权限
-g FILE:是否存在并且 拥有sgid权限
-k FILE:是否存在并且 拥有sticky权限
文件是否有内容:
-s FILE:是否存在并且 有内容
时间戳:
-N FILE:文件自从上一次读操作后是否被修改过
从属关系测试:
-O FILE:当前用户是否为文件的属主
-G FILE:当前用户是否属于文件的属组
双目测试:
FILE1 -ef FILE2:FILE1与FILE2是否指向同一个文件系统的相同inode的硬链接
FILE1 -nt FILE2:FILE1是否新于FILE2
FILE1 -ot FILE2:FILE1是否旧于FILE2
组合测试条件:
逻辑运算:
第一种方式:
COMMAND1 && COMMAND2
COMMAND1 || COMMAND2
!COMMAND
[ -O FILE ] && [ -r FILE ]
第二种方式:
EXPRESSION1 -a EXPRESSION2
EXPRESSION1 -o EXPRESSION2
!EXPRESSION
当前用户是否是文件的属主,并且拥有可执行权限:
[ -O FILE -a -x FILE ]
参考:https://www.runoob.com/linux/linux-shell-basic-operators.html