shell脚本语言编程之bash
shell简介
什么是shell: shell是Linux的用户界面,提供了用户与内核进行交互的接口,他接收了用户的指令,并将指令送入内核去执行 shell即是一种高级程序语言,也是一种命令解析语言 shell脚本有点: 开发简单、可移植性强(使用POSIX所定义的功能)、简单性 shell编程: 用于系统管理工作,或是结合现有的程序或命令完成小型的或特定的工作。 编程语言分类以及工作原理 编译语言:高级语言-- >编译器-- >目标代码 编译语言源代码运行时需要编译器转换成程序文件,编译语言举例: java, C# 解释语言:高级语言-- >解释器-- >机器代码 由解析器直接读入代码,将其转换成内部形式 ,解析语言举例:shell, perl, python 编译模型: 过程式:以指令为中心,数据服务于代码 面向对象式:以数据为中心指令服务于数据 shell编程格式: 首行shebang机制 #!/bin/bash shell脚本用途: 自动化常用命令 执行系统管理和故障排除 创建简单的应用程序 处理文本或文件
创建shell脚本
第一步:创建本文文件,首行添加#!/bin/bash #注释 第二步:运行脚本
shell脚本运行
一、给予执行权限,在命令行上指定脚本的绝对或相对路径 二、直接运行解释器,将脚本作为解释器程序的参数运行
shell脚本第一个实例:hello word
bash脚本调试
bash - n /path/to/some_script 检测脚本中的语法错误 bash - x /path/to/some_script 调试执行
脚本变量
变量:命名的内存空间 数据存储方式: 字符: 数值:整型,浮点型 作用: 1、数据存储格式 2、参与的运算 3、表示的数据范围 类型: 字符 数值:整型、浮点型 变量命名法则: 1、不能使程序中的保留字:例如if, for; 2、只能使用数字、字母及下划线,且不能以数字开头 3、见名知义 4、统一命名规则:驼峰命名法 shell中变量属于弱引用,无须指定类型,默认均为字符型;参与运算会自动进行隐式类型转换;变量无须事先定义可直接调用 如: bash 不支持浮点数 bash中的变量种类 本地变量:仅对当前shell进程生效 环境变量:对当前shell以及子shell生效 局部变量:生效范围为当前shell进程中某代码片断(通常指函数) 位置变量:$1, $2, ...来表示,用于让脚本在脚本代码中调用通过命令行传递给它的参数 特殊变量:$?, $0, $*, $@, $#
本地变量
变量赋值: name=‘value’, 以下是变量可引用的值: 1、可以是直接字串:name=“root"(注意等号左右两边不能有空格哦) 2、变量引用:name="$USER" 3、命令引用:name=`COMMAND`, name=$(COMMAND) 变量引用: ${name}, $name 三种引号使用!!!!! "":弱引用,其中的变量引用会被替换为变量值 '':强引用,其中的变量引用不会被替换为变量值,而保持原字符串 ``:能识别命令 显示已定义的所有变量: set 删除变量: unset name
证明环境变量只能在当前shell中使用
在当前shell中定义变量name=wangNN ——>在打开一个子shell输出name变量为空 pstree :显示进程树。可以查看当前终端shell的结构
bash脚本编程小试牛刀:
1、编写脚本/root/bin/systeminfo.sh,显示当前主机系统信息,包括主机名, IPv4地址,操作系统版本,内核版本,CPU型号,内存大 硬盘大小。
[root@centos7 bin]# cat systeminfo.sh #!/bin/bash echo "the hostname is:`hostname`" echo "localhost IPV4 is:`ifconfig |sed -n "2p" |sed -e "s@.*inet@@" -e "s@netmask.*@@" `" echo "the operation bersion is:`cat /etc/centos-release`" echo "the kenel information is:`uname -r`" echo "the cpu is:`lscpu |head -1|sed "s@.*[[:space:]]\+\b@@"`" echo "the member size is:`cat /proc/meminfo |head -1 |tr -s " "|cut -d " " -f 2,3`" echo "the hard /dev/sda size is:`fdisk -l |grep sda|head -1|sed "s@.*:@@"|sed "s/,.*//"`" echo "the hard /dev/sdb size is:`fdisk -l |grep sdb|head -1|sed "s@.*:@@"|sed "s/,.*//"`" [root@centos7 bin]#
2、编写脚本/root/bin/backup.sh,可实现每日将/etc/目录备份到/root/etcYYYY- mm- dd中
3、编写脚本/root/bin/disk.sh,显示当前硬盘分区中空间利用率最大的值
4、编写脚本/root/bin/links.sh,显示正连接本主机的每个远程主机的IPv4地址和连接数,并按连接数从大到小排序
环境变量
变量声明和赋值 export name="value" declare -x 变量名=值 变量引用 $name ${name} 显示所有环境变量 env export printenv 删除变量:unset 变量名
证明环境变量可以在子shell中应用
定义环境变量——>bash 进入子shell ——>echo $name发现变量有值
只读变量:
只读变量:只能声明,不能删除,退出当前shell之后自动消失
位置参数变量
$?:上一条执行命令结果,0成功1代表失败 $0:当前shell类型 $@:将传递的参数展开成多个参数 $*:将传递的参数作为一个整体 $#:目前进程中的参数个数
$*和$@区别
$*和$@都指传递多个参数,单独打印时,不能看出区别,当下一个脚本调用时$@ 将传递的参数展开成多个,$*将多个参数捆绑在一起
只有添加" "他们才会有区别,不加" "$*默认将多个参数展开成多个参数进行传递
bash中的算数运算符
+, - , *(使用时需要\进行转义), /, %取模(取余) , **(乘方) bash 中实现算数运算的几种方法: 1、let var=算数表达式 2、var=$[算数表达式] 3、var=$((算数表达式)) 4、var=$(expr $num1 + $num2 ) 5、declare -i var=数值 echo "算数表达式" |bc (如果是数值 1+2 可以是用'',如果引用的是变量就要使用"$num1+$num2") bash有内建的随机数生成器: $RANDOM( 1 - 32767) echo $[$RANDOM%50] : 0- 49之间随机数
实现算数运算的方法
1、使用let let:求算是表达式中的值
2、使用[] [:内置命令,判断条件表达式,与test同义,但是必须使用]结尾。
3、使用(())
4、使用expr expr :只能计算整数,并且表达式每个参数之间要添加空格
赋值
增强型赋值: +=, - =, *=, /=, %= let count+=3 自加3后自赋值 自增,自减: let var+=1 let var++ let var- =1 let var--
练习二
练习 1:写一个脚本/root/bin/sumid.sh,计算/etc/passwd文件中的第10个用户和第20用户的ID之和
[root@centos7 bin]# cat sumid.sh #!/bin/bash #author:wangNanNan #time:20160810 #fuction:calculate the sum of the two userID userID1=`cat /etc/passwd |sed -n "10p" |cut -d: -f3` userID2=`cat /etc/passwd |sed -n "20p" |cut -d: -f3` SUM=$[userID1+userID2] echo "the sum of he tenth userID and the twenth usrID is:$SUM" unset userID1 unset userID2 unset SUM [root@centos7 bin]#
练习 2:写一个脚本/root/bin/sumspace.sh,传递两个文件路径作为参数给脚本,计算这两个文件中所有空白行之和
[root@centos7 bin]# cat sumspace.sh #!/bin/bash #author:wangnannan #time:20160810 #function:calculate the sumspace of the two file fistFileSpace=`grep -c '^$' $1 ` secondFileSpace=`grep -c '^$' $2 ` sum=$[ fistFileSpace + secondFileSpace ] echo "两个文件空白行之和为:$sum" unset fistFileSpace unset secondFileSpace unset sum [root@centos7 bin]#
练习 3:写一个脚本/root/bin/sumfile.sh,统计/etc, /var,/usr目录中共有多少个一级子目录和文件
逻辑运算符
非:! 与:& 或:|
与:两个数字或条件进项进行与运算,其中有一个为假,结果为假
或:两个数字或条件进项进行与运算,其中有一个为真,结果为真
短路与: 第一个为0,结果必定为0; 第一个为1,第二个必须要参与运算; 短路或: 第一个为1,结果必定为1; 第一个为0,第二个必须要参与运算; 异或: ^ 异或的两个值,相同为假,不同为真
聚合命令
复合式: date; who | wc - l 命令会一个接一个地运行 • 子shell: (date; who | wc - l ) >>/tmp/trace所有的输出都被发送给单个STDOUT和STDERR
退出状态
进程使用退出状态来报告成功或失败 0:代表成功 1-255:代表失败 例如: $ ping - c1 - W1 hostdown &> /dev/null $ echo $? 自定义bash退出状态码 exit[n]; shell 脚本遇到exit,会立即退出,退出状态码取决于exit[]后面的数字,如果未定义,取决于脚本最后一条命令执行的状态码
条件测试
测试命令: • test EXPRESSION • [ EXPRESSION ] • [[ EXPRESSION ]] 注意: EXPRESSION前后必须有空白字符 test命令:检测文件类型或比较值是否相等 格式:test 表达式 test命令两种格式: 长格式:test $A=$B 短格式:[ "$A" == "$B" ] 数值类测试: -eq:是否等于 -ge:是否大于等于 -le:是否小于等于 -gt:是否大于 -lt:是否小于 -ne:是否不等于 字符串类测试: ==:是否等于; >: ascii码是否大于ascii码 <: 是否小于 !=: 是否不等于 =~: 左侧字符串是否能够被右侧的PATTERN所匹配,此表达式一般用于[[ ]]中; - z "STRING":字符串是否为空,空为真,不空为假 - n "STRING":字符串是否不空,不空为真,空为假 注意:用于字符串比较时的用到的操作数都应该使用引号
练习题:
1、写一个脚本/root/bin/argsnum.sh,接受一个文件路径作为参数;如果参数个数小于1,则提示用户“至少应该给一个参数”,并立即退出; 如果参数个数不小于1,则显示第一个参数所指向的文件中的空白行数 [root@centos7 bin]# cat argsum.sh #!/bin/bash #author=wangnannan #time=20160810 #function:argument count [[ $# -lt 1 ]] && echo "Should at least give a parameter;`exit`" || echo "the first file Blank row :`grep -c "^$" $1`" [root@centos7 bin]#
2、写一个脚本/root/bin/hostping.sh,接受一个主机的IPv4地址做为参数,测试是否可连通。如果能ping通,则提 示用户“该IP地址可访问”;如果不可ping通,则提示用户“该IP地址不可访问 ” [root@centos7 bin]# cat hostping.sh #!/bin/bash #author:wangnannan #time20160810 #fuction:test one host can bi communicate echo -e "please input the ipv4\c" read ipv4 ping -c1 $ipv4 && echo "the host can be arrive" || echo "the host no arrive" [root@centos7 bin]#
文件测试
存在性测试 - 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: 是否存在且可执行 文件特殊权限测试: - 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;
文件测试小练习:
1、检测文件是否存在
2、检测两个文件是否为硬链接
组合测试:
第一种方式: COMMAND1 && COMMAND2 并且 COMMAND1 || COMMAND2 或者 ! COMMAND 非 如: [ - e FILE ] && [ - r FILE ] 第二种方式: EXPRESSION1 - a EXPRESSION2 并且 EXPRESSION1 - o EXPRESSION2 或者 ! EXPRESSION 必须使用测试命令进行; [ - z “$HOSTNAME” - o $HOSTNAME "==\"localhost.localdomain" ] && hostname www.magedu.com
练习题
1、 chmod - rw /tmp/file1,编写脚本/root/bin/per.sh,判断当前用户对/tmp/fiile1文件 是否不可读且不可写 [root@centos7 bin]# cat per.sh #!/bin/bash [ ! -r /tmp/file1 -a ! -w /tmp/file1 ] && echo "`whoami` can not read and not write " || echo "`whoami` can read or write " [root@centos7 bin]# 注意:在普通用户下去运行,root不受权限限制 2、编写脚本/root/bin/nologin.sh和login.sh,实现禁止和充许普通用户登录系统。 [root@centos7 bin]# cat login.sh #!/bin/bash [ -a /etc/nologin ] && echo "common user is not login" || (touch /etc/nologin;echo "add file complete") [root@centos7 bin]#
使用read命令接受输入参数
read [option]
-p:不换行接受输入
-t:接受输入时间,超过指定时间将推出程序
终极练习
1、指定文件做为参数,判断文件是否为.sh后缀,如果是,添加x权限 [root@centos7 bin]# cat file.sh #!/bin/bash echo -e "please input filename:\c" read filename ! [ -e $filename ] && echo "the file not exit;" && exit ! [[ $filename == "/.*(\.sh)\b/" ]] && echo "please input .sh file;`exit`" [ -x $filename ] && echo "the file have x" || chmod +x $filename [root@centos7 bin]#
2、判断输入的IP是否为合法IP [root@centos7 bin]# cat ipcheck.sh #!/bin/bash #author:wangnannan read -p "please input IPv4:" ipv4 echo $ipv4 |egrep -q "^(\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>.){3}\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>$" && echo "ip legal" || echo "this ip is not legal" [root@centos7 bin]# vim ipcheck.sh [root@centos7 bin]#
3、计算1~100的值
[root@centos7 bin]# cat sum100.sh #!/bin/sh #author:wangnannan #description:sum 1-100 echo "caculate 1-100 sum:" for i in {1..100};do sum=$[$sum+$i] done echo "sum is:$sum" exit [root@centos7 bin]# 方法二 [root@centos7 bin]# cat sum1002.sh #!/bin/bash int=`seq 1 100` echo $int |tr " " "+" |bc [root@centos7 bin]# 方法三 [root@centos7 bin]# seq -s + 1 100 |bc 5050 [root@centos7 bin]#
4、输入起始值A和最后值B,计算从A+(A+1)...+(B-1)+B的总和 [root@centos7 bin]# cat AB.sh #!/bin/bash read -p "plese the first num:" A read -p "plese the second num:" B [ $A -gt $B ] && echo "input error" && exit ||echo "A..B的和:` seq -s + $A $B |bc`" [root@centos7 bin]#
原创文章,作者:wangnannan,如若转载,请注明出处:http://www.178linux.com/33909
评论列表(1条)
文章内容清晰,图文并貌,内容丰满,有理论有实践,