续Shell脚本学习 Day2
字符串截取补充
通配符
1 | a*z |
表示匹配a开头,中间任意字符,z结尾
使用案例
1 | # 从头匹配最短字符串 |
字符串截取应用案例
删除文件名
首先,我们创建一些演示文件
1 | mkdir sub_str #创建一个sub_str目录 |
要求:去除文件中的_finished字符
法一 一个一个直接修改
1 | mv demo_1_finished.jpg demo_1.jpg |
法二 使用字符串替换
1 | f=demo_1_finished.jpg |
法三 使用字符串替换批量处理
1 | for file_name in `ls *fin*jpg *fin*png `;do mv $file_name ${file_name//_finished/};done #不使用反引号 |
这里用到了通配符的知识
特殊shell拓展变量
- 当变量值为空,返回word字符串;当变量值非空,返回变量值
1 | ${vars:-word} |
演示
1 | [root@localhost sub_str]# vars= |
- 当变量值为空,返回word字符串,并将word赋值给变量;当变量值非空,返回变量值
1 | ${vars:=word} |
演示
1 | [root@localhost sub_str] |
- 当变量为空,返回word字符串作为stderr;当变量值非空,返回变量值
1 | ${vars:?word} |
演示
1 | [root@localhost sub_str]# vars= |
- 当变量为空,什么也不做;当变量非空,返回word字符串
1 | ${vars:+word} |
演示
1 | [root@localhost sub_str] |
实际应用
数据备份、删除过期数据的脚本
使用的命令及参数:
1 | find xargs 搜索且删除 |
del_data.sh脚本,删除某个数据文件夹的备份文件,文件日期超过7天
1 | find ${dir_path:=/xxx/xxx/} -name '*.tar.gz' -type f -mtime +7|xargs rm -f |
解释
1 | 使用:=是为了解决dir_path不存在时的情况 |
父子shell拓展
父shell概念
pstree看到如下结果,就是父shell环境
1 | pstree |
ps进程管理命令
1 | ps -ef |
创建进程列表(创建子shell)
在小括号中使用命令
实例
1 | [root@localhost ~]# ls;cd /tmp/;pwd |
通过观察发现,使用不使用小括号和使用小括号执行的结果并没有区别,那么创建进程列表有什么作用呢?
↓↓↓请结合下一节↓↓↓
检测是否在子shell环境中
Linux默认有关shell的变量BASH_SUBSHELL
1 | BASH_SUBSHELL |
取值
- 0 表示当前处于父shell
- 1 表示当前处于子shell1,可以理解成儿子
- 2 表示当前处于子shell2,可以理解成孙子
- 以此类推
注意理解,这里所指的父shell、子shell是相对的!!
举个例子说明
首先创建若干个子shell
1 | bash |
1 | root 1565 1038 0 21:22 ? Ss 0:00 \_ sshd: root@pts/0 |
观察进程树结果,按照我们的理解,按理来说目前处在sh子shell中,变量BASH_SUBSHELL的值应该为非0,即处在子shell中,但是我们在sh中打印变量值发现
1 | sh-4.2# echo $BASH_SUBSHELL |
结果表明,当前我们处在父shell
!!!!what the hell??
这就是所谓相对当前环境来说的含义把!有点难理解。
如何让BASH_SUBSHELL取值为非0?
这时候就用到上面“创建进程列表”的知识了!
1 | (ls;cd /tmp/;pwd;echo $BASH_SUBSHELL) |
1 | sh-4.2# (ls;cd /tmp/;pwd;echo $BASH_SUBSHELL) |
我们可以通过小括号的嵌套实现多个子shell
1 | sh-4.2# (ls;cd /tmp/;pwd;(echo $BASH_SUBSHELL)) |
内置命令、外置命令
内置命令:系统启动时就载入内存,常驻内存,执行效率高,但占用资源
外置命令:系统从硬盘中读取程序文件,再读入内存加载
使用type命令可以查询命令类型
1 | type <命令> |
使用实例
1 | [root@localhost ~]# which cd |
外置命令
外置命令,一般为自己下载的文件系统命令,处于bash shell之外的程序
特点:一定会开启子进程进行执行
一般外置命令所处目录为
1 | /bin |
注意:并非说内置命令不能存储在以上目录中(使用which <命令> 进行查询命令所处文件夹)
如:cd命令也存储在/usr/bin/目录下
1 | [root@localhost ~]# type cd |
内置命令
内置命令与shell是一体的
特点:内置命令不会产生子进程进行执行
查询所有内置命令的命令
1 | compgen -b |
复习与内容补充
如何在脚本中输出“$”不被识别?
法一
使用转义符“\”
实例
1 | [root@localhost ~]# echo "$123" |
法二
使用单引号
实例
1 | [root@localhost ~]# echo '$123' |
shell特性
能够在命令执行结果中,再次提出结果
shell特殊符号区分
1 | ${vars} #获取vars值 |
Shell 算术运算符一览表
算术运算符 | 说明/含义 |
---|---|
+、- | 加法(或正号)、减法(或负号) |
*、/、% | 乘法、除法、取余(取模) |
** | 幂运算 |
++、– | 自增和自减,可以放在变量的前面也可以放在变量的后面 |
!、&&、|| | 逻辑非(取反)、逻辑与(and)、逻辑或(or) |
<、<=、>、>= | 比较符号(小于、小于等于、大于、大于等于) |
==、!=、= | 比较符号(相等、不相等;对于字符串,= 也可以表示相当于) |
<<、>> | 向左移位、向右移位 |
~、|、 &、^ | 按位取反、按位或、按位与、按位异或 |
=、+=、-=、*=、/=、%= | 赋值运算符,例如 a+=1 相当于 a=a+1,a-=1 相当于 a=a-1 |
shell数值计算
Shell 和其他编程语言一样,支持多种运算符,包括:
- 算数运算符
- 关系运算符
- 布尔运算符
- 字符串运算符
- 文件测试运算符
原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。
shell的一些基础命令,只支持整数运算,小数的计算需要如bc的命令才能支持!
expr 是一款表达式计算工具,使用它能完成表达式的求值操作。
例如,两个数相加(注意使用的是反引号 *`* 而不是单引号 *‘*):
算术运算符
实现数值运算的方法
双小括号操作
运算操作符/运算命令 | 说明 |
---|---|
((a=10+66))((b=a-15)) ((c=a+b)) | 这种写法可以在计算完成后给变量赋值。以 ((b=a-15)) 为例,即将 a-15 的运算结果赋值给变量 c。 注意,使用变量时不用加$ 前缀,(( )) 会自动解析变量名。 |
a=$((10+66) b=$((a-15)) c=$((a+b)) | 可以在 (( )) 前面加上$ 符号获取 (( )) 命令的执行结果,也即获取整个表达式的值。以 c=$((a+b)) 为例,即将 a+b 这个表达式的运算结果赋值给变量 c。 注意,类似 c=((a+b)) 这样的写法是错误的,不加$ 就不能取得表达式的结果。 |
((a>7 && b==c)) | (( )) 也可以进行逻辑运算,在 if 语句中常会使用逻辑运算。 |
echo $((a+10)) | 需要立即输出表达式的运算结果时,可以在 (( )) 前面加$ 符号。 |
((a=3+5, b=a+10)) | 对多个表达式同时进行计算。 |
expr 命令操作
下表列出了常用的算术运算符,假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
+ | 加法 | expr $a + $b 结果为 30。 |
- | 减法 | expr $a - $b 结果为 -10。 |
* | 乘法 | expr $a \* $b 结果为 200。 |
/ | 除法 | expr $b / $a 结果为 2。 |
% | 取余 | expr $b % $a 结果为 0。 |
= | 赋值 | a=$b 把变量 b 的值赋给 a。 |
== | 相等。用于比较两个数字,相同则返回 true。 | [ $a == $b ] 返回 false。 |
!= | 不相等。用于比较两个数字,不相同则返回 true。 | [ $a != $b ] 返回 true。 |
注意:条件表达式要放在方括号之间,并且要有空格,例如: [$a==$b] 是错误的,必须写成 **[ $a == $b ]**。
关系运算符
关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
下表列出了常用的关系运算符,假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
-eq | 检测两个数是否相等,相等返回 true。 | [ $a -eq $b ] 返回 false。 |
-ne | 检测两个数是否不相等,不相等返回 true。 | [ $a -ne $b ] 返回 true。 |
-gt | 检测左边的数是否大于右边的,如果是,则返回 true。 | [ $a -gt $b ] 返回 false。 |
-lt | 检测左边的数是否小于右边的,如果是,则返回 true。 | [ $a -lt $b ] 返回 true。 |
-ge | 检测左边的数是否大于等于右边的,如果是,则返回 true。 | [ $a -ge $b ] 返回 false。 |
-le | 检测左边的数是否小于等于右边的,如果是,则返回 true。 | [ $a -le $b ] 返回 true。 |
布尔运算符
下表列出了常用的布尔运算符,假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
! | 非运算,表达式为 true 则返回 false,否则返回 true。 | [ ! false ] 返回 true。 |
-o | 或运算,有一个表达式为 true 则返回 true。 | [ $a -lt 20 -o $b -gt 100 ] 返回 true。 |
-a | 与运算,两个表达式都为 true 才返回 true。 | [ $a -lt 20 -a $b -gt 100 ] 返回 false。 |
逻辑运算符
以下介绍 Shell 的逻辑运算符,假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
&& | 逻辑的 AND | [[ $a -lt 100 && $b -gt 100 ]] 返回 false |
|| | 逻辑的 OR | [[ $a -lt 100 || $b -gt 100 ]] 返回 true |
字符串运算符
下表列出了常用的字符串运算符,假定变量 a 为 “abc”,变量 b 为 “efg”:
运算符 | 说明 | 举例 |
---|---|---|
= | 检测两个字符串是否相等,相等返回 true。 | [ $a = $b ] 返回 false。 |
!= | 检测两个字符串是否不相等,不相等返回 true。 | [ $a != $b ] 返回 true。 |
-z | 检测字符串长度是否为0,为0返回 true。 | [ -z $a ] 返回 false。 |
-n | 检测字符串长度是否不为 0,不为 0 返回 true。 | [ -n “$a” ] 返回 true。 |
$ | 检测字符串是否不为空,不为空返回 true。 | [ $a ] 返回 true。 |
文件测试运算符
文件测试运算符用于检测 Unix 文件的各种属性。
属性检测描述如下:
操作符 | 说明 | 举例 |
---|---|---|
-b file | 检测文件是否是块设备文件,如果是,则返回 true。 | [ -b $file ] 返回 false。 |
-c file | 检测文件是否是字符设备文件,如果是,则返回 true。 | [ -c $file ] 返回 false。 |
-d file | 检测文件是否是目录,如果是,则返回 true。 | [ -d $file ] 返回 false。 |
-f file | 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 | [ -f $file ] 返回 true。 |
-g file | 检测文件是否设置了 SGID 位,如果是,则返回 true。 | [ -g $file ] 返回 false。 |
-k file | 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 | [ -k $file ] 返回 false。 |
-p file | 检测文件是否是有名管道,如果是,则返回 true。 | [ -p $file ] 返回 false。 |
-u file | 检测文件是否设置了 SUID 位,如果是,则返回 true。 | [ -u $file ] 返回 false。 |
-r file | 检测文件是否可读,如果是,则返回 true。 | [ -r $file ] 返回 true。 |
-w file | 检测文件是否可写,如果是,则返回 true。 | [ -w $file ] 返回 true。 |
-x file | 检测文件是否可执行,如果是,则返回 true。 | [ -x $file ] 返回 true。 |
-s file | 检测文件是否为空(文件大小是否大于0),不为空返回 true。 | [ -s $file ] 返回 true。 |
-e file | 检测文件(包括目录)是否存在,如果是,则返回 true。 | [ -e $file ] 返回 true。 |
其他检查符:
- -S: 判断某文件是否 socket。
- -L: 检测文件是否存在并且是一个符号链接。