一、shell脚本编程
Shell和shell脚本的区别
shell就是一个命令行解释器,它的作用就是遵循一定的语法将输入的命令加以解释并传给系统。它为用户提供了一个向Linux发送请求以便运行程序的接口系统级程序,用户可以用Shell来启动、挂起、停止甚至是编写一些程序。Shell本身是一个用C语言编写的程序,他是用户使用Linux的桥梁。
shell即是一种命令语言,优势一种程序设计语言(就是我们所说的shell脚本)。作为命令语言,它互动德解释和执行用户输入的命令;作为程序命令语言它定义了各种变量和参数,并提供了许多在高阶语言中才具有的控制结构,包括循环和分支。
(1)bash中的算术运算
操作符:+, -, *, /, %(取余),
+=, -=,*=, /=, %=
declare
-i:整型变量
-x:环境变量,类似于export
let varName='算数表达式'
varName=$[算术表达式]
varName=$((算术表达式))
varName=`expr $num1 + $num2`
示例:
(1)
# num1=5 # num2=6 # let sum="$num1*$num2" # echo $sum 30 # sum=$[num2 - num1] # echo $sum 1 # sum=`expr $num1 + $num2` # echo $sum 11 # num1=11 # num2=5 # sum=$((num1/num2)) # echo $sum 2 注意:如果计算结果中存在小数,将会被圆整; # num1=11 # num2=2 # sum=$[num1%num2] # echo $sum 1 #a=40 #a=$[a+=2] #echo $a 42 自加并赋值给自身 # a=$[a-=2] # echo $a 40 自减并赋值给自身 #a=40 # a=$[a*=2] # echo $a 80 乘等并赋值给自身 ..... (2)计算100以内所有整数之和; #!/bin/bash # declare -i sum=0 for i in {1..100}; do let sum=$[$sum+$i] done echo "The sum is: $sum." (3)分别计算100以内所有偶数之和和奇数之和; #!/bin/bash # declare -i oddSum=0, evenSum=0 for i in `seq 1 2 100`; do oddSum=$[$oddSum+$i] done for j in `seq 2 2 100`; do evenSum=$[$evenSum+$j] done echo "The even Sum is: $evenSum, the odd sum is: $oddSum"
(2)变量的类型:
本地变量:只对当前shell进程有效,对其子shell及其他shell都无效;
定义变量:[set]Var_Name="Value"
引用变量:${Var_Name}
撤销变量:unset Var_Name
局部变量:仅对局部代码生效;
local Var_Name="Value"
环境变量:对当前shell进程及其子进程有效;
export Var_Name="Value"
位置参数变量:
$0:脚本自身
(4)#!/bin/bash # echo "The sum is: $[$1+$2]" echo $0 # ./opt.sh 10 11 The sum is: 21 ./opt.sh
$1:脚本的第一个参数
$2:脚本的第二个参数
....
(5)
#!/bin/bash # echo "The sum is: $[$1+$2]" #chmod +x opt.sh #./opt.sh 10 11 The sum is: 21
特殊变量:
$#:位置参数的个数;
# ./opt.sh 10 11 9 8 The sum is: 21 4
$*,$@:引用所有的位置参数
(6)
#!/bin/bash # echo "The sum is: $[$1+$2]" echo $* echo $@ # ./opt.sh 10 11 9 8 The sum is: 21 10 11 9 8 10 11 9 8
$?:上一条命令的执行状态
状态用数字表示:
0:表示成功
1-255:失败
给变量以默认值
varName=${varName:-value}
如果varName不空,则其值不变;否则,VarName会使用value做为其值;
read:用户交互脚本;
-p:提示符
-t [n]:超时时间
(7)
#!/bin/bash # read -t 5 -p "Enter a number: " num num=${num:-0} echo $num # ./num1.sh Enter a number: 0 #上面-t指定的超时时间为5秒钟,如果执行脚本之后等5秒钟(或直接回车),就会把设定的默认值显示出来; (8)通过键盘给定一个文件的路径,来判断文件内容的类型: vim judge.sh #!/bin/bash # read -p "Enter a file path: " fileName file $fileName bash judge.sh Enter a file path: /etc/issue /etc/issue: ASCII text
二、Bash编程之条件判断:
条件判断的常用测试类型:
整数测试
字符测试
文件测试
命令状态返回值:
$?
0:真
1-255:假
逻辑运算:
与运算:
真 && 真 = 真
真 && 假 = 假
假 && 真 = 假
假 && 假 = 假
或运算:
真 || 真 = 真
真 || 假 = 真
假 || 真 = 真
假 || 假 = 假
非运算:
!真 = 假
!假 = 真
Bash中条件判断中if的使用;
单分支:
if 条件;then
分支1
fi
双分支:
if 条件;then
分支1
else
分支2
fi
多分支:
if 条件1;then
分支1;
elif 条件2;then
分支2;then
elif 条件3;then
分支3;
.....
else
分支n;
fi
示例:
(9)让用户指定一个文件,判定;如果文件有空白行,就显示空白行数,否则,就说明文件无空白行;
#!/bin/bash # read�p “Enter a file path: ” filename if grep “^$”$fileName &> /dev/null; then linesCount=`grep “^$” $fileName | wc -l` echo “$fileName has $linesCount space lines.” else echo “$fileName hava no space line.” fi
(10)
显示如下菜单:
cpu)show cpu info;
mem)show memory info;
quit)quit
Enter your options: CPU Cpu Cpu
如果用户选择cpu,则显示文件/proc/cpuinfo的信息;
无果用户选择mem,则显示文件/proc/meminfo的信息;
如果用户选择quit,则退出,并且退出吗为5;
如果用户键入其他字符,则显示位置选项,请重新执行脚本;退出码为6;
vim showinfo.sh #!/bin/bash # returnValue=0 cat << EOF cpu) print cpu infomation mem) print memory infomation quit) Quit EOF read -p "Enter your option: " userOption userOption=`echo $userOption | tr 'A-Z' 'a-z'` if [[ "$userOption" == "cpu" ]]; then cat /proc/cpuinfo elif [[ "$userOption" == "mem" ]]; then cat /proc/meminfo elif [[ "$userOption" == "quit" ]]; then echo "quit" returnValue=6 else echo "unkown option" returnValue=7 fi exit $returnValue # bash showinfo.sh cpu) print cpu infomation mem) print memory infomation quit) Quit Enter your option: Cpu processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 61 model name : Intel(R) Core(TM) i5-5200U CPU @ 2.20GHz stepping : 4 microcode : 0x12 cpu MHz : 2194.940 cache size : 3072 KB physical id : 0 ...... ## bash showinfo.sh cpu) print cpu infomation mem) print memory infomation quit) Quit Enter your option: mem MemTotal: 1001364 kB MemFree: 398512 kB MemAvailable: 605652 kB Buffers: 2164 kB Cached: 204948 kB SwapCached: 0 kB Active: 162280 kB Inactive: 102440 kB Active(anon): 67388 kB Inactive(anon): 15868 kB Active(file): 94892 kB Inactive(file): 86572 kB Unevictable: 0 kB Mlocked: 0 kB SwapTotal: 2098172 kB SwapFree: 2098172 kB Dirty: 0 kB ....... #bash showinfo.sh cpu) print cpu infomation mem) print memory infomation quit) Quit Enter your option: quit quit # echo $? 6 # bash showinfo.sh cpu) print cpu infomation mem) print memory infomation quit) Quit Enter your option: hello unkown option # echo $? 7
测试表达式:
test 测试表达式
[ 测试表达式 ]
[[ 测试表达式 ]]
1、整数测试:
-eq:是否等于
-ne:是否不等
-gt:大于
-lt:小于
-ge:大于等于
-le:小于等于
(11)判定两个数谁大谁小,整数是通过命令行参数传递;
vim j.sh #!/bin/bash # if [ $1 �gt $2 ]; then echo “The max num is $1.” else echo “The max num is $2.” fi #bash j.sh 56 34 Themax num is 56 #Bash j.sh 56 134 The max nu is 134
(12)脚本自定义退出:exit [n]
vim hello.sh #!/bin/bash # echo“hello world” exit6 echo“hello” #bash hello.sh hello world #echo $? 6
(13)判定两个数谁大谁小,参数输入错误,则自定义退出,整数是通过命令行参数传递;
vimj.sh #!/bin/bash # if [ $# -lt 2 ]; then echo “Stupid...” echo “Usage: `basename $0` argu1 argu2” exit 4 fi if[ $1 �gt $2 ]; then echo “The max num is $1.” else echo “The max num is $2” fi #bash j.sh 3 Stupid... Usage:j.sh argu1 argu2 #bash j.sh 3 6 The max num is 6
(14)让用户通过键盘输入一个用户名,如果用户存在,就显示其用户名和UID;否则,就显示用户不存在;
#!/bin/bash # read �t 10 �p “Enter a username: ”username if id $userName &> /dev/null; then userID=`id �u $userName` echo “$userName: $userID” else echo “$userName not exist.” fi
(15)让用户通过键盘输入一个用户名,如果用户不存在就退出;如果其UID等于其GID,就说他是“good guy” 否则,就说他是个“bad guy”;
#!/bin/bash # read -t 10 -p "Enter a username: " userName if ! id $userName &> /dev/null; then echo "$userName not exist." exit 6 fi if [ `id -u $userName` -eq `id -g $userName` ]; then echo "Good guy" else echo "Bad guy" fi
(16)添加10个用户stu1-stu10;但要先判断用户是否存在;
如果存在,就用红色显示其已经存在;
否则,就添加此用户,并绿色显示;
最后显示一共添加了几个用户;
vim user.sh #!/bin/bash # declare -i userCount=0 for i in {1..10}; do if id stu$i &> /dev/null; then echo -e "\033[31mstu$i\033[0m exists." else useradd stu$i && echo -e "add \033[32mstu$i\033[0m finished." let userCount++ fi done echo "Add $userCount users." # bash user.sh add stu1 finished. add stu2 finished. add stu3 finished. add stu4 finished. add stu5 finished. add stu6 finished. add stu7 finished. add stu8 finished. add stu9 finished. add stu10 finished. Add 10 users.
2、字符测试
双目:
>:大于
<:小于
==:等于,等值比较
=~:左侧字符串是否能够被右侧的PATTREN所匹配(包含)
==:
# stringA="root" # stringB="root" # [ "$stringA" == "$stringB" ] # echo $? 0 测试是否相等?结果是肯定的。
=~: 测试userName变量中的值是否包含了“ot”这样的字符串;
# userName=root # [[ "$userName" =~ ot ]] # echo $? 0
给一个用户名,判断这个用户的shell是不是以“sh”结尾的;
#userName=root #$[[ `grep "^$userName\>" /etc/passwd | cut -d: -f7` =~ sh$ ]] #echo $? 0
单目:
-n $stringVar:字符串是否不空,不空为真,空则为假;
测试stringA是否非空,非空为真,否则为假;
#stringA=root # [ -n "$stringA" ] # echo $? 0
-z $stringVar: 字符串是否为空,空则为真,不空则假;
测试stringA是否为空,空则真,否则为假;
# [ -z "$stringA" ] # echo $? 1
3、文件测试
测试表达式:
test 测试表达式
[ 测试表达式 ]
[[ 测试表达式 ]]
单目测试:
-e file:测试文件是否存在;存在为真,否则为假;
-a file: 和-e一样
文件类型测试
-f /path/to/file:测试是否为普通文件;
-d /path/to/somefile:测试是否为目录文件;
-b /path/to/somefile:测试文件是否存在并且是否是一个块设备文件;
-c /path/to/somefile:测试是否为字符设备文件;
-h或者-L /path/to/somefile:测试文件是否存在并且为符号链接文件;
-p /path/to/somefile:测试文件是否存在并且为管道文件;
-S /path/to/somefile:测试文件是否存在并且为套接字文件;
-s /path/to/somefile:测试文件是否不空,不空为真,否则为假;
文件的权限测试:
-r /path/to/somefile:测试当前用户对此文件是否有读权限;
-w /path/to/somefile:测试当前用户对此文件是否有写权限;
-x /path/to/somefile:测试当前用户对此文件是否有执行权限;
双目测试:
file1 -nt file2:测试file1是否比file2更新一些;
file1 -ef file2: 是否指向同一文件系统的相同inode的硬链接;
file1 -ot file2: file1文件是否旧于file2
示例:
(17)
#vim download.sh #!/bin/bash # url=`http://172.16.0.1/centos6.5.repo` which wget &> /dev/null || exit 5 downloader=`which wget` [ -x $downloader ] || exit 6 $downloader $url #bash download.sh
(18)
分别复制/var/log下的文件至/tmp/logs/目录中;
复制目录时,才使用cp -r
复制文件时,才使用cp
复制链接文件,使用cp -d
如果是其他文件,使用cp -a
vim cplog.sh #!/bin/bash # targetDir='/tmp/logs' [ -e $targetDir ] || mkdir $targetDir for fileName in /var/log/*; do if [ -d $fileName ]; then copyCommand='cp -r' elif [ -f $fileName ]; then copyCommand='cp' elif [ -h $fileName ]; then copyCommand='cp -d' else copyCommand='cp -a' fi $copyCommand $fileName $targetDir done