1. 为什么要学习shell编程?
许多人会问,为什么要学习shell脚本编程?我学的是linux,又不是编程,其实对于个人用户可能用处不是很大,但是当你在为公司的成千上完的服务器做维护时,可能没有shell编程的话可能把人累死也无法完成任务,一千台服务器要做相同的工作,总不能在一千台服务器上敲一遍命令,况且人在做大量的无聊的工作极易犯错。又或者你需要在晚上3点备份数据库,你不可能晚上爬起来开电脑连接到公司服务器上去操作吧,这个写个脚本加到crontab 完事,当你写了shell脚本,执行一遍就能轻松解决这样的问题。
2. shell脚本基础:
shell脚本是包含一些命令或声明,并符合一定格式的文本文件首行shebang机制:(声明解释器,否则使用当前shell的默认解释器,为了避免发生错误强烈建议不要省略)一般使用#作为注释内容,但是除了行首除外,如下为三种声明:
#!/bin/bash #!/usr/bin/python #!/usr/bin/perl
shell脚本一般用文本编辑器创建,并给文件赋予执行权限(也可以用bash解释器解释执行),bash命令可以解释脚本。
范例:
#!/bin/bash #author:jackcui #description: first bash script //描述信息 echo “hello world!” //打印hello world! 调试运行: bash -n /root/bin/first_script //检查脚本中语法错误 bash -x / root/bin/first_script //调试执行
3. 变量(命令的内存空间):
(1)变量类型
字符型:数字,字母,下划线等
数值型:整型,浮点型
(2)本地变量:对当前shell生效,对其子shell等无效
可以是直接字符串:name=”root”
变量引用:name=$USER 如果USER变量后面还有字符,要用{}括起来,$是引用变量相当于变量存放的值,给变量赋值时,前面是变量本身,后面用变量赋值时后面时用的变量的值要加$
命令引用:name`COMMAND`
注释:引号的使用类似于正则表达式,可以使用set,unset显示定义的所有变量
(3)环境变量:对当前shell及其子shell生效
对设置了本地变量的变量使用export或declare进行声明
export name=root
一般可以使用export或env显示所有的环境变量,unset取消变量的声明
declare –x name=root
(4)局部变量:对某一断代码生效
(5)位置变量:用$1,$2,${10}表示用于脚本运行时传递给它的参数
(6)特殊变量:$?, $0, $*,$@,$#表示和参数相关的变量
4. 算术运算:
bash支持算术运算,不支持浮点运算:+ – * / % ** (加,减,乘,除,取模,乘方)乘法符号有时需要转义
(1)let var=算术表达式 eg:let sum=3+5
(2)var=$[算术表达式] eg: $[3+5]
(3)var=$((算术表达式)) eg: $((3+5))
(4)declare –i var=5
(5)var=$(expr arg1 arg2 arg3)
(6)echo ‘算术表达式’ |bc
(7)产生随机数:echo $ [$RANDOM%50]产生0-49之间的随机数因为是对50取余数,random范围(1-32767)
5. 逻辑运算:(true 1,false 0)
与:全1为1
或:有1为1
非:取反
短路与&&:第一个操作数为0,结果为0,第一操作数为1,第二操作数要运算
短路或:第一操作数为1结果为1,第一操作数为0,计算第二操作数
异或^:两个操作数相同为假,不同为真
6. 聚集命令:
(1) ;为分割符聚集 date; who |wc –l
(2)()打开子shell,命令执行完,退出子shell。 (date;who |wc -l)>> /tmp/trace
(3){} 在当前shell执行,但是第一个括号后要加空格,最后一个命令之间要加分号
eg:
[root@centos7 ~]# { ls -l /root/bin|head -n3; ls -ld /root/bin;} total 72 -rwxr-xr-x. 1 root root 315 Aug 13 15:39 A2Bsum.sh -rwxr-xr-x. 1 root root 214 Aug 13 11:02 argsnum.sh drwxr-sr-x. 2 root root 4096 Aug 14 16:27 /root/bin
7. 增强赋值:
+= -= *= /= %= ++ —
8. 退出状态:
0表示成功,1-255表示失败。 eg :ll a.txt ;echo $? 可以看到上一个命令是否执行成功,可以在bash脚本自定义退出码,根据退出码,判断在哪里出错,类似于网页404
9. 字符串测试比较:
== 是否等于,两边都应该是字符串,不能使用正则表达式
> 是否大于
< 是否小于
!= 支持正则表达式
=~ 左侧字符串能否被右边的匹配,支持正则表达式
-z 字符串是否为空,空为真
-n 字符串是否非空,非空为真
注释:使用 判断[[ ]] ,使用正则表达式不能使用””括正则表达式
示例:
(1)==示例:
[root@centos7 ~]# a=root [root@centos7 ~]# [[ $a == root ]] [root@centos7 ~]# echo $? 0 [root@centos7 ~]#
(2)> < 比较ASCII码大小:
[root@centos7 ~]# a=roou [root@centos7 ~]# [[ $a < root ]] [root@centos7 ~]# echo $? 1 [root@centos7 ~]# [[ $a > root ]] [root@centos7 ~]# echo $? 0 [root@centos7 ~]#
(3)=~ -z -n
[root@centos7 ~]# a=341234 [root@centos7 ~]# [[ $a =~ [[:digit:]]+ ]] [root@centos7 ~]# echo $? 0 [root@centos7 ~]# [[ -z $a ]] [root@centos7 ~]# echo $? 1 [root@centos7 ~]# [[ -n $a ]] [root@centos7 ~]# echo $? 0 [root@centos7 ~]#
10. 文件测试:
(1)存在行测试:
-a file 同-e 文件是否存在
(2)存在性及其类别测试,先判断是否存在,然后是是否为符合条件(8种类型的文件都能测试):
-b 是否为块设备文件
-c 是否为字符设备
-d 是否是目录文件
-f 是否为普通文件
-h 同-L 存在是否是符号链接
-p 是否为管道文件
-S 是否为管道文件
文件权限测试(先判断是否存在,再判断权限):
-r 是否可读
-w 是否可写
-x 是否可执行
-g 是否拥有sgid
-u 是否拥有suid权限
-k 是否拥有sticky权限
(3)大小及访问测试:
-s 是否存在且非空
-N 文件从上一次读取之后是否被修改过
-O 当前有效用户是否是文件属主
-G当前有效用户是否是文件属组
11. 组合测试:&& || ! -a -o
[root@centos7 bin]# [ $USER == "jack" -o $USER == "root" ] [root@centos7 bin]# echo $? 0 [root@centos7 bin]# echo $USER root [root@centos7 bin]#
12. 使用read命令接受输入
[root@centos7 ~]# cat cc.sh #!/bin/bash read -p "read some var: " aa bb dd echo "aa is: $aa bb is: $bb dd is: $dd " [root@centos7 ~]# bash cc.sh read some var: aa bb cc dd ee aa is: aa bb is: bb dd is: cc dd ee
注释:读入变量时每一个read定义的变量都会对应一个输入,最后一个变量接受剩余的输入,-p打印提示信息 ,-t超时时间
13. 条件选择if语句:
(1)单分支:
格式:
if 判断条件 ; then
条件为真的分支代码
fi
(2)双分支:
格式:
if 判断条件 ; then
条件为真的分支代码
else
条件为假的分支代码
fi
(3)多分支:
格式:
if 判断条件1 ; then
条件1为真分支代码
elif 判断条件2 ; then
条件2为真的分支代码
else
所有条件为假的分支代码
fi
示例:
[root@centos7 testdir]# cat /testdir/multiif.sh #!/bin/bash #author:jackcui if [ "$USER" == "root" ];then echo "hello root!" elif [ "$USER" == "jack" ];then echo "hello jack! how are you?" else echo "YOU ARE NOT PERMISION LOGIN!" fi [root@centos7 testdir]# bash multiif.sh hello root! [root@centos7 testdir]# chmod a+x multiif.sh [root@centos7 testdir]# su - jack Last login: Thu Aug 11 21:52:45 CST 2016 on pts/1 [jack@centos7 ~]$ bash /testdir/multiif.sh hello jack! how are you?
14. 条件判断:case语句:
格式:
case 变量引用 in
pat1)
分支1
;;
pat2)
分支2
;;
*)
默认分支
;;
esac
示例:
[root@centos7 testdir]# cat caseTest.sh #!/bin/bash #author:jackcui read -p "Input conditional number: " con case $con in [124]) echo "this is first condition!" ;; 3) echo "this is third condition!" ;; 5) echo "this is 5th condition!" ;; *) echo "this conditional is false!" ;; esac
补充:case支持glob风格的通配符 * ? [] a|b
* 任意长度字符,?任意单个字符 [] 指定给范围内的任意单个字符 a|b a或b
15.各种循环for,while,until
(1)for
格式:
for 变量名 in 列表;do
循环体
done
补充:in后的列表:1)直接给出列表。2){1..100},给出连续范围。3)$(seq 起始 递增 结束) 。4)使用通配符如*.conf 。5)变量引用 $@ , $*
for循环打印9*9乘法表
[root@centos7 bin]# cat 9\*9.sh #!/bin/bash i=1 j=1 for i in {1..9};do for j in `seq 1 $i`;do let mul=$i*$j echo -ne " $j*$i=$mul\t" done echo -e "\n" done
for循环打印国际棋盘(支持输入颜色代码,支持任意大小,颜色代码41-47,
重置=0,黑色=40,红色=41,绿色=42,黄色=43,蓝色=44,洋红=45,青色=46,白色=47 )
#!/bin/bash #author:jackcui read -p "please input width,color1 color2: " width col1 col2 for ((i=1;i<=8;i++));do for ((k=1;k<=width;k++));do for ((j=1;j<=8;j++));do for ((m=1;m<=width;m++));do let rem=(i+j)%2 if [ $rem -eq 0 ];then echo -en "\e[${col1}m \e[0m" else echo -en "\e[${col2}m \e[0m" fi done done echo -en "\n" done done
(2)while先判断条件是否满足,true则执行循环,否则跳出循环
格式:
while条件;do
循环体
done
示例:
while打印1-100的和
#!/bin/bash #author:jackcui i=1 while ((i<=100));do (( sum+=i++ )) done echo "the sum is : $sum"
(3)until false进入循环,直到条件满足就跳出循环
格式:
until 条件;do
循环体
done
until示例:
[root@centos7 bin]# cat until99.sh #!/bin/bash i=1;j=1;sum=0 until [ $i -gt 9 ];do until [ $j -gt $i ];do ((sum=j*i)) echo -ne "$j*$i=$sum\t" ((j++)) done echo "" ((j=1)) ((i++)) done
原创文章,作者:jack_cui,如若转载,请注明出处:http://www.178linux.com/37215