shell脚本
1.脚本介绍
1.1 shell脚本基础
- shell脚本:
包含一些命令或声明,并符合一定格式的文本文件 - 格式要求:首行shebang机制
#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl - shell脚本的用途有:
自动化常用命令
执行系统管理和故障排除
创建简单的应用程序
处理文本或文件
1.2 创建shell脚本
- 第一步:使用文本编辑器来创建文件文件
第一行必须包括shell声明序列:#!
#!/bin/bash
添加注注释:注释以#开头 - 第二步:运行脚本
给予执行权限,在命令行指定脚本的绝对或相对路径
直接运行解释器,将脚本作为解释器程序的参数运行(没有执行权限也可以)
eg: vim /data/bash.sh chomd +x /data/bash.sh bahs.sh 可用看做外部命令(不在PATH路径下找不到文件因此不能执行) /data/bash/sh 绝对路径执行 cd /data/ 相对路径执行 ./bash.sh cat hello.sh | bash cat /var/www/html/hello.sh(192.168.20.128) curl http://192.168.20.128/hello.sh(远程运行)
1.3 脚本规范
-
第一行一般为调用使用的语言
-
程序名,避免更改文件名为无法找到正确的文件
-
版本号
-
更改后的时间
-
作用相关信息
-
该程序的作用,及注意事项
-
最后是各版本的更新简要说明
#!/bin/bash #-------------------------------- #filename : hello.sh #revision: 1.1 #date: 2019/10/5 #autor: wang #email: wang@gmail.com #website: www.magedu.com #description: This is the first script #---------------------------------- #copyright: 2019 wang #license: GPL echo "hello world "
1.4 脚本的基本结构
1.脚本的基本结构
#!shebang
configuration_variables
function_definitions
main_code
1.5脚本调试
- 检查脚本中的语法错误:
bash -n /path/to/some_script - 调试执行
bash -x /path/to/some_script
2.变量
2.1 变量
- 变量:命令的内存空间
数据存储方式:
字符:
数值:整型,浮点型 - 变量:变量类型
作用:
1.数据存储格式
2.参与的运算
3.表示的数据范围
类型:
字符
数值:整型、浮点型 - 强类型:变量不经过强制转化,它永远是这个数据类型,不允许隐式的类型转换。一般定义变量是时
必须符合类型要求,调用未声明变量会产生错误
如 Java,c# - 弱类型:语言的运行时会隐式做数据类型转换。无须指定类型,默认均为字符型;参与运算会自动
进行隐式类型转换;变量无须事先定义可直接调用
如:bash不支持浮点数,PHP - 变量命令法则
不能使用程序中的保留字: 例如if,for
只能使用数字、字母及下划线,且不能以数字开头
见名知义
同一命名规则:驼峰命名法
2.2 bash中变量的种类
根据变量的生效范围等标准划分下面变量类型:
1. 局部变量:生效范围为当前shell进程;对当前shell之外的其他shell进程。包括当前shell的子shell进程 均无效 2. 环境(全局)变量:生效范围为当前shell进程及其子进程 3. 本地变量:生效范围为当前shell进程中某代码片段,通常指函数 4. 位置变量:$1,$2,$3....来表示,用于让脚本在代码中国调用通过命令行传递给它的参数 5. 特殊变量:$?,$0,$@,$#,$$
2.3 局部变量:
- 变量赋值:name=‘value’
- 可以使用引用value:
可以是直接字符串:name= “root”
变量引用:name= " U S E R " 命 令 引 用 : n a m e = ‘ c o m m a n d ‘ n a m e = USER" 命令引用:name=`command` name= USER"命令引用:name=‘command‘name=(command) - 变量引用:$(name)
n
a
m
e
"
"
:
弱
引
用
,
其
中
的
变
量
引
用
会
被
替
换
为
变
量
值
′
′
:
强
引
用
,
其
中
的
变
量
引
用
不
会
被
替
换
为
变
量
值
,
而
保
持
原
字
符
串
e
c
h
o
"
name "": 弱引用,其中的变量引用会被替换为变量值 '' : 强引用,其中的变量引用不会被替换为变量值,而保持原字符串 echo "
name"":弱引用,其中的变量引用会被替换为变量值′′:强引用,其中的变量引用不会被替换为变量值,而保持原字符串echo"name" 保留格式
echo $name 不保留格式 - 显示已定义的所有变量:set
- 删除变量:unset name
2.4环境变量
-
变量声明、赋值:
export name=VALUE
declare -x name=VALUE -
变量引用: $name , $(name)
-
显示所有环境变量:
env
printenv
export
declare -x -
删除变量:
unset name -
bash内建的环境变量:
PATH
SHELL
USER
UID
HOME
PWD
SHLVL
LANG
HOSTNAME
HISTSIZE
2.5 只读和位置变量
- 只读变量:只能声明,但不能修改和删除
声明只读变量:
readonly name
declare name
查看只读变量:
readonly -p - 位置变量:在脚本代码中调用通过命令行传递给脚本的参数
$1,$2,…:对应第1、2参数,shift[n[换位置
$0 :命令本身
$*:传递给脚本的所有参数,全部参数合为一个字符串
$@:传递给脚本的所有参数,每个参数为独立字符串
$#:传递给脚本的参数的个数
@ @ @*只在被双引号包起来的时候才会有差异
set --清空所有位置变量
eg: (umask 666; touch /data/f1) 一次性任务,开启子shell,执行后结束,不影响当前环境 (name=wang;echo $name) echo $name {name=mage;echo $name;} {}影响当前环境 echo $name x=1;echo "pid=$$";(echo"subpid=$$";echo "subx=$x"; x=2;echo "subx2=$x");echo x=$x
2.6 退出状态:
- 进程使用退出状态来报告成功或失败
0代表成功,1-255代表失败
$?变量保存最近的命令退出状态 - 例如:
ping -c1 -W1hostdowm &> /dev/null
ehco $? - bash自定义退出状态码
exit[n]:自定义退出状态码
注意:脚本中一旦遇到exit命令,脚本会 立即终止;终止退出状态取决于exit命令后面的数字
注意:如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码
3. 运算
3.1 算法运算:
-
bash中的算术运算:help let
+,-,*,/,%取模(取余),**(乘方) 实现算法运算: let var=算术表达式 var=$[算术表达式] var=$((算术表达式)) var=$(expr arg1 and arg3...) declare -i var=数值 echo ‘算术表达式’ | bc
-
乘法符号有些场景中需要转义,如*
-
bash有内建的随机数生成器:$RANDOM (0-32767)
echo $[$RANDOM%50]
:0-49之间随机数
3.2 赋值
- 增强型赋值:
+=,-=,*=,/= ,%= - let varOPERvalue
例如:let count+3= 自加3后自赋值 - 自增,自减:
let var+=1
let var++
let var-=1
let var–
3.3 逻辑运算
- 非:!
!1=0
!0=1 - 短路运算
短路与:&&
第一个为0,结果必为0
第一个为1,第二个必须参与运算
短路或: ||
第一个为1,结果必为1
第一个为0,第二个必须参与运算 - 异或:^
异或的两个值,相同为假,不同为真
0^1=1
0^0=0
1^0=1
1^1=0
a=$[a^b];b=$[a^b];a=$[a^b];echo $a $b
互换值 - true,false
1,0 - 与:&
1&1=1
1&0=1
0&1=0
0&0=0 - 或:|
1|1=1
1|0=1
0|1=1
0|0=0
4.条件测试
4.1 条件测试
- 判断某需求是否满足,需要由测试机制来实现
专用的测试表达式需要由测试命令辅助完成测试过程 - 评估布尔声明,以便用在条件性执行中
若真,则返回0
若假,则返回1 - 测试命令:
test EXPRESSION
[EXPRESSION]
注意:EXPRESSION前后必须有空白字符窜
4.2 bash的字符串测试
-eq 是否等于 -ne 是否不等于 -gt 是否大于 -lt 是否小于 -le 是否等于或小于 -ge 是否大于或等于 = 比较字符串内容是否相同 != 比较字符串内容是否不同 =~ 左侧字符串是否能够被右侧的pattern所匹配 -z“string”字符串是否为空,空为真,不空位假 -n "string" 字符串是否不空,不空为真,空位假 注意:用于字符串比较时的用到的操作数应该使用引号
4.3 条件性的执行操作符
-
根据退出状态而定,命令可以有条件地执行
&&代表条件性的AND THEN
||代表条件性的OR ELSE -
例如:
grep -q no_such_user /etc/passwd || echo 'No such user' NO shch user ping -c1 -W2 station &> /dev/null && echo "station1 is up " || (echo 'station1 is unreachable';exit 1) station1 is up
4.4 test命令
- 长格式的例子:
test "$A" = "$B" && echo "strings are equal"
test "$A" -eq "$B" && echo "strings are equal"
- 简要格式的例子:
[ "$A" = "$B" ] && echo "strings are equal"
[ "$A" -eq "$B" ] && echo "strings are equal"
4.5 bash的文件测试
- 存在性测试
-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: 执行 - 文件特殊权限测试:
-u file:是否存在且拥有suid权限
-g file: sgid权限
-k file: sticky权限 - 文件大小测试:
-s file:是否存在非空 - 文件是否打开:
-t fd:fd 文件描述是否在某终端已经打开
-N file: 文件自从上一次被读取之后是否被修改过
-O file:当前有效用户是否为文件属组
-G file:当前有效用户是否为文件属组 - 双目测试
file1 -ef file2 : file1 是否是file2 的硬链接
file1 -nt file2:file1是否新于file2(Mtime)
file1 -ot file2 : file1是否旧于file2
4.6 bash的组合测试条件
- 第一种方式:
command1 && command2 并且
command1 || command2 或者
!command 非
如 [[ -t file ] && [ [ -w file ]] - 第二种方式:
expression1 -a expression2 并且
expression1 -o expression3
!expression
必须使用测试命令进行 - 示例:
[ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab
4.6 使用read命令来接受输入
使用read 来把输入值分配给一个或多个shell变量
-p: 指定要显示的提示 -s: 静默输入,一般用于密码 -n N 指定输入的字符长度N -d ‘字符’输入结束符 -t N timeout 为N秒 read 从标准输入中读取值,给每个单词分配一个变量 所有剩余单词都被分配给最后一个变量 read -p "enter a filename:" FILE
ifconfig ens333 | grep -Eo" \>(([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])\>"
5.配置用户环境
5.1 防止扩展
- 反斜杠()会使随后的字符按原意解释
$echo Your cost:$5.00 - 加引号来防止扩展
单引号(’)防止所有扩展
双引号("")也防止所有扩展,但是以下情况例外:
$(美元符号) —— 变量扩展
`(反引号) —— 命令替换
(反斜线) —— 禁止单个字符扩展
!(叹号) —— 历史命令替换
5.2 bash的配置文件
1)全局配置:
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc
2)个人配置:
~/.bash_profile
~~/.bashrc
5.3shell登录两者方式
- 交互式登录:
直接通过终端输入账号密码登录
使用“su - UserName ”切换的用户
执行顺序:/etc/profile–> /etc/profile.d/ - 非交互式登录:
su UserName
图形界面下打开的终端
执行脚本
任何其他的bash示例
执行顺序:~/.bashrc–>/etc/bashrc–>/etc/profile.d/*.sh
5.4修改配置文件生效
- 修改profile和bashrc文件后生效
两种方法:
重新启动shell进程
.或source
例如: . ~/.bashrc
5.5 profile 类
- 按照功能划分,存在两类:
profile类和bashrc类 - profile类:为交互式登录的shell提供配置
全局:/etc/profile,/etc/profile.d/*.sh
个人:~/.bash_profile
功能:
用于定义环境变量
运行命令或脚本 - bash退出任务
1)保存在~./.bash_logout文件中(用户)
2)在退出登录shell时运行
3)用于创建自动备份,清除临时文件
5.6$-变量
- h: hashall,打开这个选项后,shell会将命令所在的路径hash下来,避免每次都要查询。通过set+h将h选项关闭
- i: interactive-comments,包含这个选项说明当前的shell是一个交互式的shell。所谓的交互式shell,在脚本中,i选项是关闭的
- m:monitor,打开监控模式,就可以通过Job control来控制进程的停止、继续,后台或者前台执行等。
- 4)B:braceexpand,大括号扩展
- H:history,H选项打开,可以展开历史列表中的命令,可以通过!感叹号来完成,例如“!!”返回上最近的一个历史命令,"!n"
5.7 bash如何展开命令行
- 把命令行分成单个命令词
- 展开别名
- 展开大括号的声明({})
- 展开波浪符声明(~)
- 命令替换$()和 ``)
- 再次把命令分成命令词
- 展开文件通配(*、?、[abc]等)
- 准备 I/O重定向(<>)
- 运行命令