shell 脚本: 基于过去式 ,解释执行的语言
shell 脚本的用处
自动化常用命令,执行系统管理和故障排除, 创造简单的应用程序,处理文本或文件
shell 脚本的基本结构
系统命令的组合 , 变量 ,表达式 ,控制语句 ,
shell脚本要以.sh结尾,
#!/bin/bash # 首行必须这么写,shebang机制。告诉这个脚本用bash执行,不同shell写法不同如:#!/bin/csh
shell脚本里#(井号)为注释,但第一行的特殊
脚本写完后要加执行权限
运行脚本:vi qq.sh 里面开头 #! /bin/bash
./xx.sh 相对路径
/opt/xx.sh 绝对路径
或bash xx.sh
命令执行过程:
先看是否是个别名,如果不是再看是否为内部命令,还不是找外部命令,如果还没有则报错:command not found
在运行时还可以执行远程服务器上的脚本
脚本调试
语法检查(只检查语法不执行)
bash -n script.sh
显示执行过程(逻辑错误)
bash -x script.sh
或自己阶段性输出
命令写错了后面的命令也会执行
脚本错误总结
语法错误 (bash -n)
命令错误
逻辑错误 (bash -x)
变量:
变量用来存放数据,
变量表示命名的内存空间,将数据放在内存,空间中,通过变量名来获取里面的资料,数据,
不同变量存放的数据不同,决定了,(数据储存方式,参与的运算,表示的数据范围)
变量的数据类型
1;字符,2;字符串,3;数组
数值
1;整型,2;浮点型
脚本语言在定义变量时通常不需要指明类型,直接就可以,在 bash shell 中,每一个变量的值都是字符串,不管你给变量时有没有使用引号,值都会以字符串的形式储存
Bash shell 在默认情况下不会区分变量类型,即使你将整数和小数赋值给变量,它们也会被视为字符。
变量名由数字,字母,下划线组成,
必须以字母或下划线开头。不能以数字开头,不能使用—线,主机名不能使用"_"。不能使用 Shell 里的关键字或shell里的命令
变量定义和引用
普通变量:生效范围为当前shell进程,对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效
环境变量: 生效范围为当前shell进程及其子进程
本地变量:生效范围为当前shell进程中某代码片断,通常指函数
#pstree
几个重要的参数:
-A: 各进程树之间的连接以ASCII码字符来连接
-U:各进程树之间的连接以utf8字符来连接,某些终端可能会有错误
-p:同时列出每个进程的PID
-u: 同时列出每个进程的所属账号名称:
在linux中
使用ps命令可以查看有哪些进程在运行和运行的状态、
进程是否结束、进程有没有僵尸、哪些进程占用了过多的资
ps命令最常用的是用于监控后台进程的工作情况.
1. 运行2. 中断。3. 不可中断。4. 僵死。5. 停止
D 不可中断。R 运行 s,静止状态。T。 停止 Z 。僵死 W: 没有足够的记忆体分页可分配
<: 高优先序的行程
N: 低优先序的行程
L: 有记忆体分页分配并锁在记忆体内
变量定义和引用
普通变量:生效范围为当前shell进程,对当前shell之外的其他shell进程,包括当前shell的子shell进程均无效,
环境变量:生效范围为当前shell进程及其子进程
本地变量:生效范围为当前shell进程中某代码片段,通常指函数
变量的值可以用以下多种形式;
直接字符串:a=1 files=/tmp/*
变量引用; name1="$name'
命令引用:name=·date·或name=$(date)
查看全部变量(包括系统自带)
set
取消变量
ynset name
变量值临时生效,退出终端,失效
在shell的变量中,双引号的细节
[root@bogon~]#a=`seq 1 10`
[root@bogon~]#echo $a
1 2 3 4 5 6 7 8 9 10
[root@bogon~]#echo "$a"
1
.
.
10
d
变量的引用
$name
${name}
一般情况用$name 方式就足够了,什么时候用${}
把两个变量用_下划线链接
echo $name_$date
echo ${name}_$date
环境变量:可以使子进程继承父进程中的变量,但是不能反过来。如果子进程修改了父进
程中的变量,那么子进程的子进程会继承修改的那个值
可以用pstree查看进程树
查环境变量
env或export
位置变量
ls 后面跟不同的参数执行出的结果不同,脚本是否也可以跟不同的参数
.
/xx.sh a b c
$1 , $2,$3…..
对应第 1 个,第 2 个,第 3 个参数
$0 命令本身包括路径
$
*
传递给脚本的所有参数,全部参数合为一个字符串
$@ 传递给脚本的所有参数,全部参数为独立字符串
$# 传递给脚本的参数的个数
$
*
和$@只在被双引号包起来的时候才会有差异
清空位置参数 ;set --
命令的执行顺序
{} ~ $()或者··
文件通配符 *,?,[abc]
重定向:
命令执行
转移:
\会吧后面的字符按原文解释
脚本安全和set
set命令可以定制shell环境
环境变量中有$-变量
[root@bogon~]# echo $-
himBH
h:hashell ,如果这个关咯,就不缓存外部命令,set+h,后hash命令呗禁用
i:包含这个选项,说明当前shell是个交互性 的,shell在sheell脚本 i 中,是关闭的
m:打开监控模式,可以通过jop control 来控制进程的停止,继续,后台,前台运行,打开后,ctrl+z 命令实现,脚本安全
B:花括号 echo{1.。10},关咯,set+B,{}作用没啦
H:历史命令,把它关咯无法使用! 10 set+H set-H
set 命令实现脚本安全
-e:如果在脚本中遇到错误就退出,后面的不执行,(主要是能很好地止损,里面的每个命令都要写正确)
-u: 在没有设置变量时,报错
-x: 脚本执行时,打印命令及其参数,类似,bash-x
-o:显示set支持的选项
-o:选项,打开某选项、
+o:关闭,关闭选项
printf
类似增强版的echo
替换符 功能
%s 子符串
%f 浮点格式
%d,%i 十进制整数
%o 八进制
%u 不带正负号的十进制
%x 十六进制(a-f)
%X 十六进制(A-F)
%% %本身
%c ASCLL字符
%b 如果对应参数中包含转移字符时,可以使用此字符替换,进行转移
常用转移符号
转义符, 功能
\a 警告字符
\b 后退
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
\f 换页
\ 表身 \ 本身
算数运算
shell支持算数运算,但只支持整数,不支持小数
bash 中的算数运算
+-*/%2**
乘号在有些场景中要转移
内建的随机数生成器变量:
$RANDOM 聚值范围 0-32767
如何支持小数:
echo “scale=2;10/3”|bc
逻辑运算
True,false 真假
1 0
与& 与 0 相与,结果为 0,与 1 相与,结果保留原值
1 与 1=1
1 与 0=0
0 与 1=0
0 与 0=0
和 1 相或结果为 1, 或 0 相或,结果保留原值
1 或 1=1
1 或 0=1
0 或 1=1
0 或 0=0
非 !
!1 =0 !true
!0 =1 !false
异或^
异或的两个值,相同为假,不同为真
1^1=0
1^0=1
0^1=1
0^0=0
短路与:
条件a& 条件b
如果条件 a 为假,结果是不是已经为假了。所以就不用判断条件 b 了
如果条件 a 为真,这时 条件 b 才参与运算 短路或:
条件a| 条件b
如果条件 a 为真,结果是不是已经为真了。所以就不用判断条件 b 了
如果条件 a 为假,这时条件 b 才参与运算
数值测试
-gt 是否大于
-ge 是否大于等于 -eq 是否等于
-ne 是否不等于 -lt 是否小于
-le 是否小于等于
字符串测试
-z string 字符串是否为空,没定义或值是空为真,不空为假 -n string 字符串是否是不空,空为假,不空为真
= 是否等于
!= 不等于
> 是否大于(以 ascii 码来判断大小)
< 是否小于
以上都要注意空格
[[]]:
== 左侧字符串是否和右侧的pattern是否相等,pattern为通配符
=~ 左侧字符串是否能够被右侧的正侧表达的pattern所匹配
[[]] 中使用的是扩展的正则 是否以。log结尾
使用正则表达式时用两个中括号,平时用单个中括
在[[ ]]中 如果 pattern*用双引号引起来,则*表示是符号的自身,不引则表示是通配符
文件测试
-a file 或 -e file : 文件是否存在,存在为真,不存在为假
-b file :是否存在且为块设备文件
-c file : 是否存在且为字符设备文件
-d file : 是否存在且为目录
-f file : 是否存在且为普通文件
-h file :或-L :是否存在且为符号链接文件
-p file: 是否存在且为管道文件
-s file: 是否存在且为套接字文件
也可以取反 【!-f file】
权限测试(判断的是实际权限,包括特殊权限chattr)
-r file :判断是否存在且有读权限
-w file :判断是否存在且有写得权限
-x file: 判断是否存在有执行权限
-u file : 是否在且拥有suid权限
-g file: 是否在且拥有suid权限
-k file: 是否在且拥有sticky权限
文件属性测试
-s file: 是否存在且非空
-t fd: 文件描述符是否在某终端已经打开
-N file: 文件自上一次被读取之后是否被修改过
-O file: 当前有效用户是否为文件属主
-G file: 当前有效用户是否为文件属组
file1 -ef file2 :1 是否为 2 的硬链接
file1 - nt file2 : 1 是否新于 2(访问时间)
file1 - ot file2 : 1 是否旧于
()和{}都可以将多个命令组合在一起,批量执行
()会开启子进程,而且会继承父进程变量
{}不会开启子进程
组合测试条件
-
a [ expr1
-
a expr2 ] 并且, 都为真则为真
-o [ expr1-o expr2 ] 或者,一个为真则为真
! [ ! expr2 ] 取反
-a 与 and
-o 或 or
-a-o 只能在[] 中,不能在[[]]中使用
从标准输入里读取数据
read
-p 指定要显示的提示
-s 静默输入,输入的时候无法显示
-n N 指定输入的字符长度 N
-t N Timeout 为 N 秒
-d‘字符'输入结束符
bash 的配置文件
全局配置
个人配置
~/.bash_profile
~/.bashrc
shell 登录的两种方法
交互模式
通过终端输入用户密码登录
通过 su-user 切换过来的用户(完全切换,带环境变量)
su
-
user 切换时执行的顺序:
/etc/profile—> /etc/profile.d/*.sh—>~/.bash_profile—>~/.bashrc—> /etc/bashrc
一个 shell 脚本运行时,会开启一个子进程,在脚本执行完后回收子进程。source 命令可以让脚本在当前 shell 下执行,不开启子进source 功能等同于. (点)
非交互模式:
su user
图形里开终端
执行脚本
执行其他的 bash 实例
执行顺序
/etc/profile.d/*.sh—> /etc/bashrc—>~/.bashrc
profile 和 bashrc
profile
为交互式登录的 shell 提示配置
全局: /etc/profile, /etc/profile.d/*.sh
个人:~/.bash_profile
功能:
定义环境变量
运行命令或脚本
bashrc
为非交互式和交互式登录的 shell 提供配置
全局: /etc/bashrc
个人:~/.bashrc
功能:
定义命令别名和函数
定义本地的变量
修改完profile 和bashrc 后生效的方法
重新启动shell进程
souece或。配置文件
bash 退出时要执行的命令在.bash_logout文件中,在退出shell时运行,可以用来清理垃圾
控制语句
条件判断:if
判断一个账户是否存在
格式:
if 判断条件:then
为真的代码
fi
双分支
if 判断条件 1 :then
为真的代码
esle
为真的代码
fi
多分支
条件1为真的代码
elif 判断条件 2:then
条件2为真的代码
else
以上条件都不满足,执行的代码
fi
说明多个条件时,逐个条件进行判断,第一次遇到真时,执行分真支,然后到结束
if可以箱套
缩进:set et;set ts =4
算身体的BMI
条件判断:case
case 关键字或变量 in
pat) 分支1
........
)*
默认分支
;;
esac
case 支持 glob 风格的通配符
*任意长度任意字符
?任意单个字符
[]指定范围内的任意单个字符
| 或
循环:
将某段代码重复运行多次,通常有进入循环和结束循环的条件
重复运行次数
循环次数已知
循环次数未知
常见循环的命令: for while until
for 循环