shell脚本编程
shell脚本是包含一些命令或声明,并符合一定格式的文本文件
shell脚本的用途有:
-
自动化常用命令
-
执行系统管理和故障排除
-
创建简单的应用程序
-
处理文本或文件
命令查询过程:别名–>内部变量–>hash–>$PATH
~]#bash -n 检测脚本语法错误
~]#bash -x 顺序检查调试执行
程序的组成:指令+数据 程序编程风格: 1、过程式:以指令为中心,数据服务于指令 2、对象式:以数据为中心,指令服务于数据
编程逻辑处理方式:顺序执行、循环执行、选择执行
变量
什么是变量:是一段命名的内存空间
变量数据类型: 1、字符型 2、数值:整型,浮点型
如何创建shell脚本
使用文本编辑器来创建文本文件 第一行必须包括shell声明序列:#!/bin/bash 可以自行添加注释,注释以#开头
运行脚本,给予执行权限,在命令行上指定脚本的绝对或相对路径,直接运行解释器,将脚本作为解释器程序的参数运行
编程程序语言分类
强类型:
定义变量时必须指定类型、参与运算必须符合类型要求;调用未声明变量会产生错误
弱类型
无须指定类型,默认均为字符类型;参与运算会自动进行隐式类型转换;变量无须事先定义可直接调用
编程语言变量命名法则:
不能使用程序中的保留字:例如if、for
只能使用数字、字母及下划线,且不能以数字开头
见名知义
统一命名规则:驼峰命名法
Bash中变量的种类
根据变量的生效范围等标准分:
本地变量:生效范围为当前shell进程;对当前shell之外的其他shell进程,包括当前shell子shell进程均无效
环境变量:生效范围为当前shell进程及其子进程
局部变量:生效范围为当前shell进程某代码片段(通常指函数)
位置变量:$1,$2,…来表示,用于让脚本在脚本代码中调用通过命令行传递给它的参数
特殊变量:$?,$0,$*,$@,$#
本地变量:
变量赋值:name='value' 变量引用:name="$USER" 变量引用可分为两种 "":弱引用,其中的变量引用会被替换为变量值 '':强引用,其中的变量引用不会被替换为变量值,而保持原字符串 命令引用:name=`COMMAND`,name=$(COMMAND) 显示已定义的所有变量:set 删除定义的变量:unset name
环境变量
环境变量声明、赋值 export name=value declare -x name=value 变量引用方式:$name,${name} 显示所有环境变量:export、env、printenv 删除变量:unset name Bash有许多内建的环境变量: PATH:可执行文件的搜索路径,决定了shell将到哪些目录中寻找命令或程序。 SHELL:当前登录用户shell类型 USER:当前登录用户 UID:当前登录用户ID HISTSIZE:历史命令记录数,定义了history命令输出的记录数,即输出.bash_history文件中的最后HISTSIZE行 HISTFILESIZE:定义了在~/.bash_history中保存命令的记录总数 HISTFILE:历史命令记录的配置文件,它是隐藏文件 HOME:当前用户主目录 PWD:当前工作目录 OLDPWD:之前工作目录 PS1:一级命令提示符 PS2:使用转义字符,第二行出现的提示符
只读变量
语法:readonly (option)(arguments) readonly命令用于定义只读shell变量和shell函数,只能声明,不能删除和修改。 ~]#readonly -p 输出显示系统中所有定义的只读变量 -f 定义只读函数 -a 定义只读数组变量 变量定义:readonly name declare -r name 注意:只对当前shell有效,注销后清除
位置变量
在脚本代码中调用通过命令行传递给脚本的参数: $1,$2,...:对应第1、第位参数,shift[n]换位置 $0 命令本身 $* 传递给脚本的所有参数。全部参数合为一个字符串 $@:传递给脚本的所有参数,每个参数为独立字符串 $#:传递到脚本的参数的个数 $$:脚本运行的当前进程ID号 注意:$@,$*只在被双引号引起来的时候才会有差异 双引号括起来的情况:$*将所有的参数认为是一个字段,所有的位置参数,被作为一个单词 $@每个参数都是一个独立的""引用字串,这就意味着参数被完整地传递,并没有被解释和扩展,这也意味着,每个参数列表中的每个参数都被当成一个独立的单词.
示例:抄的还请见谅。
#!/bin/bash echo "-------------ISF is set to \"-seperator\" ------------" IFS="-seperator"; # 注意 seperator前有一个减号(-) for i in "$@"; do echo "@ '$i'"; done for i in "$*"; do echo "* '$i'"; done echo "-------------ISF is set to null ------------------------" IFS= for i in "$@"; do echo "@ '$i'"; done for i in "$*"; do echo "* '$i'"; done echo "-------------ISF is unset ------------------------" unset IFS for i in "$@"; do echo "@ '$i'"; done for i in "$*"; do echo "* '$i'"; done echo "---------$* and $@ are not put into double quotes(\"\")-------" for i in $@; do echo "@ '$i'"; done for i in $*; do echo "* '$i'"; done 运行结果: -------------ISF is set to "-seperator" ------------ @ '1' @ '2' @ '3' * '1-2-3' -------------ISF is set to null ------------------------ @ '1' @ '2' @ '3' * '123' -------------ISF is unset ------------------------ @ '1' @ '2' @ '3' * '1 2 3' ---------1 2 3 and 1 2 3 are not put into double quotes("")------- @ '1' @ '2' @ '3' * '1' * '2' * '3'
由此可见, 当不加双引号("")时, $*,$@被展开时的行为是一样的; 当$*,$@都被放到双引号("")内;如果设置了变量IFS的值并且该值非空, 则$*被展开时使用${IFS}的第一个字符将所有参数(除了参数$0)连接起来, 即"$1c$2c$3c...",其中c表示${IFS}的第一个字符; 如果变量IFS为空,则$*被展开时只是将所有参数(除了参数$0)简单连接起来, 即 “$1$2$3..." 如果变量IFS没有被定义,则$*被展开时使用空格字符将所有参数(除了参数$0) 连接起来, 即"$1 $2 $3 ..." 但$@的展开和没有加双引号的情形是一致的。
算术运算
bash中的算术运算: expr,let +,-,*,/,%取模(取余),**(乘方)
实现算术运算
let var=算术表达式
var=$[算术表达式]
var=$((算术表达式))
var=$(expr arg1 arg2 arg3 …)
declare -i var = 数值
echo '算术表达式' | bc
bash中有内建的随机数生成器:$RANDOM(1-32767) 示例:echo $[$RANDOM%50]:0-49之间随机数 expr 作乘法运算的时候需把*转义\*
赋值
增强型赋值型 +=,-=,*=,/=,%= let varvalue 示例:let count+=3 自加3后在赋值 自增,自减: let var+=1 let var++ let var-=1 let var--1
逻辑运算
true 为1 false 为0 与(and) & 1 与 1 = 1 1 与 0 = 0 0 与 1 = 0 0 与 0 = 0 或(or) | 1 或 1 = 1 1 或 0 = 1 0 或 1 = 1 0 或 0 = 0 非!:! 1 = 0 ! 0 = 1 异或^ 异或的两个值,相同为假,不同为真 短路运算 短路与 && 第一个为0,第二个必须要参与运算 第一个为1,结果必为1 短路或 || 第一个为1,第二个必须要参与运算 第一个为0,结果必为0 注意:可以说短路运算只能操作布尔型的,而非短路运算不仅可以操作布尔型,而且可以操作数值型。
聚齐命令
有两种聚集命令的方法 复合式:date;who | wc -l 命令会一个接一个地运行 子shell式:(date;who) | wc -l >>/tmp/trace 所有的输出都被发送给单个STDOUT和STDERR 作为一个整体
退出状态
进程使用退出状态来报告成功或失败 0 代表成功,1-255代表失败 $?特殊变量保存最近的命令退出状态 0 成功退出 >0 退出失败 1-125 命令退出失败,失败返回的相关值由程序定义(譬如,程序内退出只执行 exit 2,则返回为2) 126 命令找到了,但无法执行 127 命令找不到 >128 命令因受到信号而死亡 退出状态码 可以bash自定义退出状态码 exit [n]:自定义退出状态码 注意:脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字 如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码
ping -W(设置响应时间)
脚本中添加(置于子shell下)相当于调用一个shell脚本
条件测试
判断某需求是否满足,需要由测试机制来实现,专用的测试表达式需要由测试命令辅助完成测试过程。 评估布尔声明,以便用在条件性执行中 若真,则返回0 若假,则返回1测试命令 test expression(表达式) [ expression ] [[ expression ]] 注意:expression前后必须有空白字符 根据退出状态而定,命令可以有条件地进行 && 代表条件性的AND THEN || 代表条件下的or else
Bash的测试类型
数值测试: -gt:是否大于 -ge:是否大于等于 -eq:是否等于 -ne:是否不等于 -lt:是否小于 -le:是否小于等于字符串测试: ==:是否等于 >:ascii码是否大于ascii码 <:是否小于 !=:是否不等于 =~:左侧字符串是否能够被右侧的pattern所匹配 注意:此表达式一般用于[[ ]]中; -z "STRING":字符串是否为空,空为真,不空为假 -n "STRING":字符串是否不空,不空为真,空为假 注意:用于字符串比较时用到的操作数都应该使用引号
文件测试:
存在性测试
-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
原创文章,作者:真的可行(wzb),如若转载,请注明出处:http://www.178linux.com/33968