Shell编程学习之一
一、脚本的书写和执行
脚本第一行,顶格:#!/bin/bash
其中 #!称之为shebang,LinuxOS会的程序载入器会分析shebang后的内容,将这些内容作为解释器的指令。常见的有:#!/bin/bash,#!/usr/bin/python等。
以#开头的行都是注释的行,会被解释器忽略。
其他就是脚本的主要内容了,主要是由许多命令组成的。
脚本语法检查:bash -n 脚本名 例如:bash -n httpd
执行: bash 脚本名 或者 给脚本x权限;写出脚本的路径执行
bash -n 单步执行,可以看到脚本执行过程中的每一步
二、shell脚本执行过程
顺序执行:从上到下依次执行
选择执行:根据测试条件执行,满足某个测试条件是,执行对应的分支
循环执行:将一段代码反复执行多次。根据循环退出条件退出。
三、shell的变量类别
本地变量,环境变量,局部变量,位置变量,特殊变量。这里可能位置变量和特殊变量使用较多一些。例如:S#(参数个数),$@ $*(参数列表)。具体代表的意义请参照http://guoting.blog.51cto.com/8886857/1433602里面所说明的。
四、循环语句
常见的循环语句有for,while,until。循环的主要意义在于,重复执行近似的代码,提高代码利用率。
1)for循环:遍历有限个元素列表
for语句的语法格式:
for VAR_NAME in LIST
do
do something
done
退出条件:遍历完LIST中的所有元素
如何生成数值列表
1、{start..end} 例如{100..120}代表初始值是100,步长是1,最大值是120的整数。
2、命令引用 `seq [start [increment]] end`
seq 12 :表示初始值是1,步长是1,最大值是12的整数
seq 12,24 :表示初始值是12,步长是1,最大值是34的整数
seq 12,3,24 :表示初始值是12,步长是3,最大值是34的整数
生成列表的方式:
1、手动给个列表:
for i in 1 2 3 4 5
2、数值列表:
{start..end}
`seq [start [increment]] end`
3、$*, $@ :调用脚本参数的列表
4、命令生成列表 例如:`ls /path/to/where`
for的另一种格式,此种格式更接近C语言的for语句,格式如下:
for(( 初始条件;测试条件;修改表达式));do
循环体
done
例如:求1到100的整数之和
#!/bin/bash # description:sum 1..100 # version:0.0.0 # date:2014-07-14 # author: Alex # license: GPL let sum=0 for ((i=0;$i <= 100;i++));do let sum+=$i done echo $sum
bash如何实现算术运算:
1、定义整形变量的方法:
let VAR_NAME=VALUE 例如: let sum=0
declare -i VAR_NAME=VALUE 例如:declare -i sum=0
注意:即使没有定义为整型变量,字符型的数字依然可以参与算术运算;bash会执行变量类型的隐式类型转换;
2、实现算术运算的方式:
let VAR_NAME=ARITHMATIC_EXPRESSION
VAR_NAME=$[ARITHMATIC_EXRESSION]
VAR_NAME=$((EXPRESSION))
VAR_NAME=$(expr $num1 + $num2)
例如:实现算术3+2
let sum=3+2
sum=$[3+2]
sum=$((3+2))
sum=$(expr 3 + 2) 注意:这里的空格
3、常见的算术运算符
一般的算术运算符:+ - * / % **(乘方)
增强型的算术运算符:++ += *= /= %=
这些都是双目运算符。
练习:写一个脚本,满足以下要求:
1、创建用户tuser501-tuser510;
2、创建目录/tmp/dir-当前日期时间;
3、在/tmp/dir-当前日期时间 目录中创建9个空文件file101-file110
4、将file101的属主改为tuser501,依次类推,一直将file110的属主改为tuser510;
#!/bin/bash # Name:tuser501-510.sh # Description: testing # Version: 0.0.1 # Author: Alex # Date: 2014-07-08 dir_name="/tmp/dir-`date +%Y%m%d-%H%M%S`" /bin/mkdir $dir_name for num in {101..110};do /bin/touch $dir_name/file$num user_num=$[$num+400] /usr/sbin/useradd tuser$user_num &>/dev/null /bin/chown tuser$user_num $dir_name/file$num done echo "The result:" /bin/ls -l $dir_name [root@server scripts]# chmod +x tuser501-510.sh [root@server scripts]# bash -n tuser501-510.sh [root@server scripts]# ./tuser501-510.sh The result: total 0 -rw-r--r-- 1 tuser501 root 0 Jul 9 11:33 file101 -rw-r--r-- 1 tuser502 root 0 Jul 9 11:33 file102 -rw-r--r-- 1 tuser503 root 0 Jul 9 11:33 file103 -rw-r--r-- 1 tuser504 root 0 Jul 9 11:33 file104 -rw-r--r-- 1 tuser505 root 0 Jul 9 11:33 file105 -rw-r--r-- 1 tuser506 root 0 Jul 9 11:33 file106 -rw-r--r-- 1 tuser507 root 0 Jul 9 11:33 file107 -rw-r--r-- 1 tuser508 root 0 Jul 9 11:33 file108 -rw-r--r-- 1 tuser509 root 0 Jul 9 11:33 file109 -rw-r--r-- 1 tuser510 root 0 Jul 9 11:33 file110 [root@server scripts]#
2)while,until语句
while语句的语法格式:
while 测试条件 ;do
循环体
done
until语句的语法格式:
until 测试条件 ;do
循环体
done
while的执行过程是当测试条件为真,执行循环体语句,执行完成以后再判断测试条件,直到测试条件为假的时候退出。until的执行过程与while执行过程类似,主要区别是测试条件为假的时候执行循环体,测试条件为真的时候退出循环体。
while可以直接遍历文件,这在我们以后写脚本的过程中可能随时会用到。
格式:
while read VAR_NAME ;do
循环体
done < /path/to/somefile
练习:求100以内所有偶数整数之和
#!/bin/bash # description: the sum even of 1 to 100 # version:0.0.1 # date:2014-07-10 # author: Alex #定义求和存储变量 declare -i sum=0 #定义计数器变量,一般whlie或者是until都会引入像计数器这种机制,这样是为了更好的实现退出 let count=0 while [ $count -le 100 ];do #循环测试条件 let rst=$count%2 #判断是否为偶数 也可以这样 res=$[$count%2] #如果是偶数,则求和。这是一种短路运算,等价于if语句 # if [ $rst -eq 0 ];then # let sum+=$count #fi [ $rst -eq 0 ] && let sum+=$count let count++ #实现计数 done #输出求和结果 echo "The sum is $sum." ##until语句只需要将测试条件变为 [ $count -gt 100 ] 即可
练习:显示磁盘使用超过10%的磁盘设备和具体使用率。
#!/bin/bash # version:0.0.0 # date:2014-07-14 # author: Alex # license: GPL df | sed 1d > /tmp/res.txt #df | grep -v "Use" > /tmp/res.txt echo -e "\033[31mDisk Usage(Use > 10%):\033[0m" while read loop ;do [ `echo $loop | tr -s ' '| cut -d ' ' -f5 | tr -d '%' | grep -v "Use"` -gt 10 ] && \ echo $loop | tr -s ' '| cut -d ' ' -f1,5 done < /tmp/res.txt rm -f /tmp/res.txt #此脚本还有缺陷(像 df 命令的结果有时一个设备的信息分布在2行的情况下,此脚本还不能处理),目的是说明while是如何遍历文件的。
脚本执行结果:
补充:
有时候我们需要执行一个死循环,这就要用到 true 和 : 命令。true 命令的作用是只返回命令状态值 0 。与之对应的是 false,它的作用只返回命令状态值 1。:命令的作用是什么都不干的命令。
在循环中,有时可能会用到以下命令:
trap 'CMD1;CMD2' 信号量
break 在脚本中一般与循环一起使用,用于跳出本层循环
continue 在脚本中的作用是跳过本次循环循环,直接进入到下次循环。
具体示例:
#!/bin/bash echo "########### test break and trap ##################" read -p "Plz enter a username: " userName # 捕获 Ctrl + C 信号 trap 'echo "quit";exit 3' INT # while : ;do while true; do if who | grep "\<$userName\>" &> /dev/null; then break fi echo "wait..." sleep 5 done echo "$userName is logged." # 求 100 以内的所有奇数之和 echo "########### continue ##################" for loop in {1..100};do if [ $[$loop%2] -eq 0 ] ;then continue else let sum+=$loop fi done echo "The sum is $sum."