一、shell程序的特点
shell 程序是一门高级语言,它是解释执行编辑的指令的,程序在执行过程中先对每一行命令进行解释,解释成计算机能够识别的机器代码后,由计算机按照顺序执行。
由于是一行一行的解释执行,所以顺序执行是主要的特点。同时shell程序还支持分支判断和选择循环,这也就能够处理重复性以及较为复杂性的工作。
二、shell 脚本的结构和格式要求
shell 编辑语言的基本机构包括:各种系统命令的组合、数据存储(变量、数组)、表达式的使用、判断和循环语句。shell 编程最简单的实现就是shell语言编写的脚本程序。
脚本的格式要求:首行shebang机制。 #!/bin/bash #!/usr/bin/python #!/bin/awk
shebang机制声明了脚本中语言的格式类型,限定了命令执行的环境。添加shebang机制是最基本的,之后就可以输入一些简单的指令了。当用到一些比较多的命令完成一个任务时,为了阅读的方便,我们可以对一段命令语句的上一行或者语句后面添加注释,注释以#开头的,# 后面的命令语句在脚本运行时计算机直接忽略,不进行解释。注释也可以用来在脚本的开头添加一些有关脚本功能及编写人员的信息,让脚本具备共享性和连贯性,为脚本的后续优化提前准备。
脚本代码开头约定: 1、第一行一般为调用使用的语言
2、程序名,避免更改文件名为无法找到正确的文件
3、版本号
4、更改后的时间
5、作者相关信息
6、该程序的作用,及注意事项
7、最后是各版本的更新简要说明
shell脚本的运用会大大简化运维工作的重复性的工作内容,具体的用途包括:自动化常用命令、执行系统管理和故障排除、创建简单的应用程序、处理文本或文件。
脚本的基本结构
#!SHEBANG
CONFIGURATION_VARIABLES (配置变量)
FUNCTION_DEFINITIONS (函数定义)
MAIN_CODE
示例:一个脚本查找出给定范围数字范围内,所有的素数。
上面脚本的编写用到了变量,函数,基本的格式也是符合要求的,右侧是脚本的执行结果,功能基本以及实现,若是针对更加复杂的情形,还可以进行后续的优化,使脚本变得严谨。
当我们的脚本完成后,可能由于程序的不严谨,导致脚本的执行结果和预期有所出入,我们可以对编写的脚本进行调试检查。Linux中的bash命令就具备这也的功能:
bash -n /path/to/script_file 可以检查脚本中的语法错误
bash -x /path/to/script_file 可以逐行执行脚本中的语句,并输出执行结果,可以对脚本的执行进行调试。
三、变量
变量是一种“值”能够改变的字符表示。当变量一旦使用,它本身代表了计算机的一小块内存空间,这个内存空间,存储变量代表的“值”。可以想象成一个重复使用的快递盒,里面可以装不同的货物,当要使用到盒子里面的货物时,将盒子里面的货物取出即可。
变量可以存储的数据类型两种:字符串和数值,数值中包括了整型(整数)和浮点型(小数)。变量的功能包括:1、灵活的存储数据;2、参与运算,重复使用;3、表示一定的数据范围。
在不同的计算机语言中,变量使用规范是不尽相同的。比如shell中,变量是没有细分类型的,默认都是字符型,当一个变量存储的是数字时,运算时会自动转换数字类型进行运算,这中对变量使用没有严格的规定的变量,我们称为弱类型的变量。而python中,不同的变量会由字符型,整数型,浮点数型等等,变量的字符型和整数型的变量运算是不允许的,这中情况下的变量,我们称为强类型的变量。
变量的类型没有具体的要求的,但是变量名称是由规范的,变量命名法则:
1、不能使程序中的保留字:例如if, for
2、只能使用数字、字母及下划线,且不能以数字开头
3、见名知义
4、统一命名规则:驼峰命名法
根据变量的生效范围等标准划分下面变量类型:
局部变量:生效范围为当前shell进程;对当前shell之外的 其它shell进程,包括当前shell的子shell进程均无效
环境(全局)变量:生效范围为当前shell进程及其子进程
本地变量:生效范围为当前shell进程中某代码片断,通常指函数
位置变量:$1, $2, …来表示,用于让脚本在脚本代码 中调用通过命令行传递给它的参数
特殊变量:$?, $0, $*, $@, $#,$$
上面我们了解了变量的基本信息,但是变量和脚本有什么关系呢?这是由于,在计算机处理大量的数据时,我们不能将计算机需要的数据都一一输入到计算机,一一输入既浪费时间,也浪费计算机的内存空间和性能。本身计算机有运算的功能,我们可以输入一个初始的数值,通过一定的运算方式,让计算机自己生成可能用到的数据,但是数据也不能一直生成,却不删除,所以让变量保存不需要一直存在的数值,这也就能解决上面的困惑了。而脚本也是一样的情况。
1、局部变量
变量赋值:name=‘value’
注意:变量赋值的等号两边不可以有一个空格
要赋得值中间不能有空格,有的话需要用双引号引起
调用变量的值时,有必要使用双引号引起,防止部分信息丢失
可以使用引用value:
(1) 可以是直接字串; name=“root”
(2) 变量引用:name=”$USER”
(3) 命令引用:name=`COMMAND` name=$(COMMAND)
变量引用:${name} $name
” “:弱引用,其中的变量引用会被替换为变量值
‘ ‘:强引用,其中的变量引用不会被替换为变量值,而保持原字符串
显示已定义的所有变量:set
删除变量:unset name
2、环境变量
3、只读和位置变量
只读变量:只能声明,但不能修改和删除
声明只读变量:
readonly name
declare -r name
查看只读变量: readonly –p
位置变量:在脚本代码中调用通过命令行传递给脚本的参数
$1, $2, …:对应第1、第2等参数,shift [n]换位置 位置变量数字是两位以上的使用 ${10}
$0: 命令本身
$*: 传递给脚本的所有参数,全部参数合为一个字符串
$@: 传递给脚本的所有参数,每个参数为独立字符串
$#: 传递给脚本的参数的个数
$@ $* 只在被双引号包起来的时候才会有差异 位置变量”$*”,在脚本中,被脚本中的脚本引用时,如果有双引号,会导致变为一个整体参数,而不是原来的多个参数
set — 清空所有位置变量
4、脚本的退出状态—变量 $?
我们在命令行中输入一个命令,这个命令运行后,不管是否成功,都会有一个退出状态值,一般是无法查看到的,可以查看环境变量 $? 的值,若返回的值是 0,代表成功,若是1-255,代表失败。
在脚本中也是如此,如果未给脚本指定退出状态码,整个脚本的退出状态码 取决于脚本中执行的最后一条命令的状态码 。我们也可以通过 exit [n] 命令,自定义脚本运行的退出状态码, 注意:脚本中一旦遇到exit命令,脚本会立即终止;终止退出 状态取决于exit命令后面的数字。
5、read命令介绍
read 命令可以让用户的键盘输入,导入到指定的变量中,若是在脚本中,可以让脚本外让用户实时输入,从而实现脚本与用户交互。若是没有提供变量名,会提供给 $REPLY
常用的选项
-p 指定要输出的提示
-s 让输入的文字不可见(设置密码)
-n 指定输入的字符长度
-d 指定结束符
-t N 指定输入等待的时间
四、算数运算和逻辑运算
1、算数运算
bash中支持的算术运算包括:+, -, *, /, %取模(取余), **(乘方)等等 ,我们可以使用help let 命令查看大部分的运算符号。
实现算数运算的方法:
(1) let var=算术表达式
(2) var=$[算术表达式]
(3) var=$((算术表达式)) 算数表达式中若是变量名,可以不加 “$”表示
(4) var=$(expr arg1 arg2 arg3 …)
(5) declare –i var = 数值
(6) echo ‘算术表达式’ | bc
乘法运算符号 “ * ” 在一些场景下(正则表达、通配符)有特殊的含义,必要时需要转义使用。
bash中有一个随机数生成器 :$RANDOM 每次显示它的值,是自动随机生成的,范围是(0-32767),我们可以利用这个变量的随机性,通过取余数的运算,生成我们需要的随机数范围。
例如:echo $[RANDOM%20] 每次产生的随机数在 0-19 范围内,这是因为,对20取余数是不会大于等于20的。
运算的同时赋值的方法:
1、增强型赋值: +=, -=, *=, /=, %=
let i+=3 ; let i-=3 …… 相当于 i=$[i+3] ; i=$[i-3]
2、递增和递减:++i , –i , i++ , i–
let ++i ; let i++ 相当于 let i+=1
2、逻辑运算
逻辑运算的运算结果和算术运算不同,算数运算是得到一个数值,逻辑运算的结果不是数值,而是运算成功与否,结果只有两种:true(真)–0,false(假)–1 这里是对应bash的输出值。
逻辑运算一般是:与(-a)、或(-o)、非(!),衍生的还有短路运算:短路与(&&)、短路或(||)、异或(^)。运算规则如下(1–真、0–假,和shell是不同的):
五、条件测试
条件性测试,判断某条件是否满足,需要由测试机制来实现 , 专用的测试表达式需要由测试命令辅助完成测试过程 。
1、测试命令:
• test EXPRESSION
• [ EXPRESSION ]
• [[ EXPRESSION ]]
注意:EXPRESSION前后必须有空白字符
命令、测试命令和短路与、短路或结合,可以根据命令的退出状态码进行条件判断控制命令的执行。
EXPRESSION 包含如下:
2、数值测试 -gt 是否大于
-ge 是否大于等于
-eq 是否等于
-ne 是否不等于
-lt 是否小于
-le 是否小于等于
3、字符串测试:
== 是否等于
> ascii码是否大于ascii码
< 是否小于
!= 是否不等于
=~ 左侧字符串是否能够被右侧的PATTERN所匹配
注意: 此表达式一般用于[[ ]]中;扩展的正则表达式
-z “STRING“ 字符串是否为空,空为真,不空为假
-n “STRING“ 字符串是否不空,不空为真,空为假
注意:用于字符串比较时的用到的操作数都应该使用引号
4、文件存在性测试
-a FILE:同-e
-e FILE: 文件存在性测试,存在为真,否则为假 存在性及类别测试
-b FILE:是否存在且为块设备文件
-c FILE:是否存在且为字符设备文件
-d FILE:是否存在且为目录文件
-f FILE:是否存在且为普通文件
-h FILE 或 -L FILE:存在且为符号链接文件
-p FILE:是否存在且为命名管道文件
-S FILE:是否存在且为套接字文
5、文件权限测试:
-r FILE:是否存在且可读
-w FILE: 是否存在且可写
-x FILE: 是否存在且可执行 文件特殊权限测试:
-u FILE:是否存在且拥有suid权限
-g FILE:是否存在且拥有sgid权限
-k FILE:是否存在且拥有sticky权限
6、 文件大小测试:
-s FILE: 是否存在且非空
7、文件是否打开:
-t fd: fd 文件描述符是否在某终端已经打开
-N FILE:文件自从上一次被读取之后是否被修改过
-O FILE:当前有效用户是否为文件属主
-G FILE:当前有效用户是否为文件属组
8、双目测试:
FILE1 -ef FILE2: FILE1是否是FILE2的硬链接
FILE1 -nt FILE2: FILE1是否新于FILE2(mtime)
FILE1 -ot FILE2: FILE1是否旧于FILE2
9、组合测试条件的方式
第一种方式:
COMMAND1 && COMMAND2 并且
COMMAND1 || COMMAND2 或者
! COMMAND 非
如:[[ -r FILE ]] && [[ -w FILE ]]
第二种方式:
EXPRESSION1 -a EXPRESSION2 并且
EXPRESSION1 -o EXPRESSION2 或者
! EXPRESSION 必须使用测试命令进行
总结:根据上面两个方式,可以链接命令和判断,单中括号可以使用 -a -o ,双中括号和括号外面可以使用 && 或者||
六、防止扩展和shell登录的相关配置文件
1、防止扩展
反斜线(\)会使随后的字符按原意解释
$ echo Your cost: \$5.00
Your cost: $5.00
加引号来防止扩展
• 单引号(’)防止所有扩展
• 双引号(”)也防止所有扩展,但是以下情况例外:
$(美元符号) - 变量扩展
`(反引号) - 命令替换
\(反斜线) - 禁止单个字符扩展
!(叹号) - 历史命令替换
2、shell登录的相关配置文件
bash的配置文件
按生效范围划分,存在两类:
全局配置:
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc
个人配置:
~/.bash_profile
~/.bashrc
不同登录方式配置文件生效情况:
交互式登录:
(1)直接通过终端输入账号密码登录
(2)使用“su – UserName” 切换的用户
执行顺序:/etc/profile –> /etc/profile.d/*.sh –> ~/.bash_profile –> ~/.bashrc –> /etc/bashrc
非交互式登录:
(1)su UserName
(2)图形界面下打开的终端
(3)执行脚本
(4)任何其它的bash实例
执行顺序: ~/.bashrc –> /etc/bashrc –> /etc/profile.d/*.sh
按功能划分,存在两类:
profile类和bashrc类
profile类:为交互式登录的shell提供配置
全局:/etc/profile, /etc/profile.d/*.sh
个人:~/.bash_profile
功用:
(1) 用于定义环境变量
(2) 运行命令或脚本
bashrc类:为非交互式和交互式登录的shell提供配置
全局:/etc/bashrc
个人:~/.bashrc
功用:
(1) 定义命令别名和函数
(2) 定义本地变量
本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/90774