ShellScript脚本编程 Shell脚本入门 Shell是什么 Shell英文是”壳”,Shell是一块包裹着系统核心的壳,处于操作系统的最外层。
Shell是一个用C语言编写的程序,它是用户使用Linux的桥梁。通过编写Shell命令发送给linuⅸ内核去执行,操作就是计算机硬件,所以Shell命令是用户操作计算机硬件的桥梁,Shell是命令,类似于Windows系统中的Dos命令。
同时它可以作为命令语言 ,它交互式解释和执行用户输入的命令或者自动地解释和执行预先设定好的一连串的命令;作为程序设计语言 ,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。
为什么学习Shell脚本?
Shell脚本语言的好处是简单、易学、易用,适合处理文件和目录之类的对象,以简单的方式快速完成某些复杂的事情。通过Shell命令编程语言来提高Linux系统的管理工作效率。
Shell的运行过程
当用户下达指令给该操作系统的时候,时间上是把指令告诉shell,经过shell解释,处理后让内核做出相应的动作。系统的回应和输出的信息也由shl处理,然后显示在用户的屏幕上。
Shell解析器 查看linux系统centos支持的shell解析器
打印输出当前centos默认的解析器是bash语法:
其中:
echo:用于打印输出数据到终端
$SHELL:是全局共享的读取解析器类型环境变量,所有的Shell程序都可以读取的变量
Shell编写格式与执行方式 脚本格式
脚本文件后缀名规范
Shell脚本文件就是一个文本文件,后缀名建议使用.sh结尾。
首行格式规范
设置当前Shell脚本文件采用bash解析器运行脚本代码
注释格式
单行注释
多行注释
脚本文件执行的三种方式
添加权限:chmod a+x helloworld.sh
三种方式的区别:sh或bash执行脚本文件方式是直接使用Shell解析器运行脚本文件,不需要可执行权限,仅路径方式是执行脚本文件自己,需要可执行权限。
解释执行多个命令 案例:执行test.sh脚本,实现在/root/bjsxt/目录下创建一个onetest..txt,在onetest.txt文件中增加内容”hello onetest shell”
实现步骤:
使用mkdir
创建/root/bjsxt目录
创建脚本文件
编写脚本文件
1 2 3 4 5 # !/bin/bash # 在/root/bjsxt/目录下创建onetest.txt文件 touch /root/bjsxt/onetest.txt # 在onetest.txt文件中写入内容 echo "Hello Shell" >> /root/bjsxt/onetest.txt
执行脚本文件使用cat命令查看文件内容
Shell变量 变量用于存储管理运行在内存中的数据。
变量的类型
系统环境变量
自定义变量
特殊符号变量
系统环境变量 系统环境变量是系统提供的共享变量,是linux系统加载Shell的配置文件中定义的变量共享给所有的Shell程序使用。
Shell的配置文件分类
全局配置文件
1 2 3 /etc/profile /etc/profile.d/*.sh /etc/bashrc
个人配置文件
1 2 当前用户/.bash_profile 当前用户/.bashrc
一般情况下,我们都是直接针对全局配置进行操作。
环境变量的分类 在Liux系统中,环境变量按照其作用范围不同大致可以分为系统级环境变量和用户级环境变量。
系统级环境变量:Shell环境加载全局配置文件中的变量共享给所有用户所有Shell程序使用,全局共享。
用户级环境变量:Shell环境加载个人配置文件中的变共享当前用户的Shell程序使用,登录用户使用。
查看当前Shell系统环境变量 查看当前Shell系统环境变量,命令: env
查看所有变量 命令:set
常用系统环境变量
【示例】查看PATH环境变量
自定义变量 自定义变量分类
自定义局部变量
自定义常量
自定义全局变量
自定义局部变量 就是在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
变量定义规则
命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
中间不能有空格,可以使用下划线(_)。
不能使用Shell中的关键字作为变量名称。
在bash环境中,变量的默认类型都是字符串类型,无法直接进行数值运算。
变量的值如果有空格,必须使用双引号括起来。
定义变量语法 变量名=变量值
注意:==等号两边不能有空格==
【示例】定义局部变量
1 2 3 4 # !/bin/bash # 定义变量 a=10 your_name=jack
查看变量 查看变量的值方式:
1 2 3 4 5 # 语法1:直接使用变量名查询 $ var_name # 语法2:使用花括号 $ {var_name} # 区别:花括号方式适合拼接字符串
删除变量 使用unset命令可以删除变量。语法:
unset variable_name
变量被删除后不能再次使用。unset命令不能删除只读变量。
自定义全局变量 父子Shell环境介绍 例如:有2个Shell脚本文件A.sh和B.sh
如果在A.sh脚本文件中执行了B.sh脚本文件,那么A.sh就是父Shell环境,B.sh就是子Shell环境。
自定义全局变量 就是在当前脚本文件中定义全局变量,这个全局变量可以在当前Shell环境与子Shell环境中都可以使用
语法:
export var_namel var_name2
测试全局变量在子Shell中是否用,在父Shel中是否可用
实现步骤:
创建2个脚本文件test1.sh和test2.sh
编辑test1.sh
1 2 3 4 5 # !/bin/bash # 定义全局变量 export a=100 # 执行test2.sh脚本文件 sh test2.sh
编辑test2.sh
1 2 3 # !/bin/bash # 输出全局变量 echo "全局变量a的值:$a"
自定义系统环境变量 /etc/profile定义存储自定义系统级环境变量数据,当前用户进入Shell环境初始化的时候会加载全局配置文件/etc/profile里面的环境变量,供给所有Shell程序使用,以后只要是所有Shel‖程序或命令使用的变量,就可以定义在这个文件中。
创建环境变量步骤:
编辑/etc/profile全局配置文件
1 # 增加命令:定义变量 VAR1=VAR1,并导出为环境变量
注意: 直接打开全局配置文件是在配置文件的最顶端,使用G可以快速到文件底部,gg重新回到文件的顶端。
重新加载置文件/etc/profile,因为配置文件修改后要立刻功加载里面的数据就需要重新加载,语法:
source /etc/profile
在Shell环境中读取系统级环境变量var1
特殊符号变量
特殊符号变量:$n
$n
:用于接收脚本文件执行时传入的参数,
$0
用于获取当前脚本文件名称。
$1
~$9
代表获取第1个输入参数到第9个输入参数。
第10个以上参数获取参数的格式:${数字}
,否则无法获取。
1 2 3 4 5 6 7 8 9 10 # !/bin/bash # 测试特殊符号变量 $n echo "脚本文件名: $0" echo "第一个参数: $1" echo "第二个参数: $2" echo "第三个参数: $3" echo "第九个参数: $9" echo "第十个参数: $10" # 参数有问题 echo "第十个参数: ${10}" echo "第11个参数: ${11}"
特殊符号变量:$#
和$*
$#
是获取所有输入参数如的个数
$*(或$@)
:传递的参数作为一个字符串显示
【示例】$#
和$*
的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 # !/bin/bash # 测试特殊符号变量 $n echo "脚本文件名: $0" echo "第一个参数: $1" echo "第二个参数: $2" echo "第三个参数: $3" echo "第九个参数: $9" echo "第十个参数: $10" # 参数有问题 echo "第十个参数: ${10}" echo "第11个参数: ${11}" echo "参数的个数: $#" echo "参数:$*" echo "参数:$@"
$*
与$@
区别:
相同点:都是引用所有参数。
不同点:只有在双引号中体现出来。
$*
获取的所有参数拼接为一个字符串,格式为:"$1 $2...$n"
$@
获取一组参数列表对像,格式为:"$1" "$2"..."$n"
假设在脚本运行时写了三个参数1、2、3,则$*
等价于"123"
(传递了一个参数),而$@
等价于"1" "2" "3"
(传递了三个参数)。
1 2 3 4 5 6 7 8 9 10 11 # !/bin/bash # 测试$*与$@ 的区别 for i in "$*" do echo $i done echo "---------------" for i in "$@" do echo $i done
特殊符号变量$?
$?
用于获取上一个Shell命令的退出码,或者是函数的返回值。
每个Shell命令的执行都有一个返回值,这个返回值用于说明命令执行是否成功。一般来说,返回0代表命令代表执行成功,非0代表执行失败。
1 2 3 4 5 6 # !/bin/bash function test_add(){ echo "调用函数" return 10 } test_add
特殊符号$$$$ $$$$:用于获取当前Shell环境的进程ID号。
字符串变量 字符串创建 字符串是shell编程中最常用最有用的数据类型(除了数字和字符串,也没啥其它类型好用了),字符串可以用单引号 ,也可以用双引号,也可以不用引号 。
【示例】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # !/bin/bash # 创建字符串使用单引号 a='aaaa' echo $a echo ${a} # 创建字符串使用双引号 b="bbb" echo $b # 创建字符串不使用引号 c=ccc echo $c # d=aa bb # echo $d # 注意如果变量的值中间有空格,需要使用引号创建 d="aa bb" echo $d
三者区别:
1 2 3 4 5 6 7 8 9 10 11 12 # !/bin/bash a='aaaa' # 输出字符串变量 echo 'hellosa' echo "hello$a" echo "hello\"$a\"" echo hello$a echo "hello $a" echo hello $a # 赋值给其他变量 str1="hello$a" # str1=hello $a
获取字符串的长度 获取字符串长度语法:
${#字符串变量名}`
1 2 3 4 5 6 # !/bin/bash # 获取字符串长度 a="abc" b="123456" echo "字符串变量a的值:$a, 长度:${#a}" echo "字符串变量b的值:${b}, 长度:${#b}"

##### 字符串的拼接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # !/bin/bash name="jack" age=22 # 无符号拼接 str=$name$age echo $str # 双引号拼接 str="$name$age" echo $str # 混合拼接 str=$name','$age echo $str # 字符串拼接中间有空格需要使用双号 str="$name $age" echo $str # 不支持,需要使用引号 # str=$name $age # echo 输出字符串中间可以有空格echo $name $age
##### 截取字符串
| 格式 | 说明 |
| ------------------------ | ------------------------------------------------------------ |
| ${变量名:start:length} | 从string字符串的左边第start个字符开始,向右截取length个字符。 start从0开始 |
| ${变量名:start} | 从string字符串的左边第start个字符开始截取,直到最后 |
| ${变量名:0-start:length} | 从string字符串的右边第start个字符开始,向右截 取length个字符,stat从1开始,代表右侧第一个字符 |
| ${变量名:0-start} | 从string字符串的右边第start个字符开始截取,直到最后 |
| ${变量名#*chars} | 从string字符串左边第一次出现`*chars`的位置开始, 截取`*chars`右边的所有字符 |
| ${变量名##*chars} | 从string字符串左边最后一次出现`*chars`的位置开 始,截取`*chars`右边的所有字符 |
| # ${变量名%chars*} | 从string字符串右边第一次出现`chars*`的位置开始, 截取`chars*`左边的所有字符 |
| # ${变量名%%chars*} | 从string字符串右边最后一次出现`chars*`的位置开 始,截取`chars*`左边的所有字符 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 # !/bin/bash # 截取字符串 ${变量名:start:length} str="abcdefgabc" sub_str=${str:1:3} echo "sub_str:$sub_str" # ${变量名:start} sub_str=${str:2} echo "sub_str:$sub_str" # ${变量名:0-start:length} sub_str=${str:0-3:5} echo "sub_str:$sub_str" # ${变量名:0-start} sub_str=${str:0-4} echo "sub_str:$sub_str" # ${变量名#*chars} 不包括第一次出现的charssub_str=${str#*a} echo "sub_str:$sub_str" # ${变量名##*chars} 不包括最后一次出现的charssub_str=${str##*a} echo "sub_str:$sub_str" # ${变量名%chars*} 不包括第一次出现的charssub_str=${str%b*} echo "sub_str:$sub_str" # ${变量名%%chars*} 不包括最后一次出现的charssub_str=${str%%b*} echo "sub_str:$sub_str"

#### 数组变量
bash支持一维数组(不支持多维数组),并且没有限定数组的大小。
类似于C语言,数组元素的下标由0开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于0。
##### 定义数组
在Shell中,用括号来表示数组,数组元素用"空格"符号分开。定义数组的一般形式为:
`array_name=(value0 value1 value2 value3)`
数组的值类型任意,个数不限
可以不使用连续的下标,而且下标的范围没有限制。
`array_name=([0]=value0 [3]=value3 [5]=value5)`
##### 读取数组
读取数组元素值的一般格式是:
`${数组名[下标]}`
@或*获取数组中的所有元素
`$(array_name[@])`
`$(array_name[*])`
获取数组的长度或个数
`$(#array_name[@])`
`$(#array_name[*]`
获取数组指定元素的字符长度
`${#array_name[索引]}`
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # !/bin/bash # 定义数组 arr1=(21 33 "abc" '123') arr2=(1 2 3 4) arr3=([0]=10 [1]=20 [3]=30 [4]=40 [6]=60) # 根据下标获取数组元素的值 echo "获取arr1数组第1个元素的值:${arr1[0]}" echo "获取arr3数组第7个元素的值:${arr3[6]}" # 获取数组中的所有元素 echo "获取arr1数组中的所有元素:${arr1[@]}" echo "获取arr2数组中的所有元素:${arr2[*]}" # 获取数组的长度 echo "获取arr1数组的长度:${#arr1[@]}" echo "获取arr2数组的长度:${#arr2[*]}" # 获取数组指定元素的字符长度 echo "获取arr1数组中第4个元素的长度:${#arr1[3]}"
##### 数组拼接
所谓的数组拼接就是将两个数组连接成一个数组。
语法:使用`@`和`*`获取数组所有元素之后进行拼接。
`new_array=(${array1[@]} ${array2[@]} ...)`
`new_array=(${array1[*])} ${array2[*]} ...)`
1 2 3 4 5 6 7 8 9 10 # !/bin/bash # 定义数组 arr1=(1 2 3 4 5 6) arr2=(a b c d e f g) echo "输出数组中所有元素:" echo "arr1数组中的所有元素:${arr1[@]}" echo "arr2数组中的所有元素:${arr2[*]}" echo "数组的拼接:" new_arr=(${arr1[@]} ${arr2[*]}) echo "拼接后数组:${new_arr[*]}"
##### 数组删除
删除数组可以删哪除数组中指定元素,也可以删除整个数组。
删除数组中指定元素语法格式:
`unset array_name[index]`
删除整个数组
`unset array_name`
1 2 3 4 5 6 7 8 9 10 11 12 13 # !/bin/bash # 定义数组 arr1=(1 2 3 4 5 6) arr2=(a b c d e f g) echo "输出数组中所有元素:" echo "arr1数组中的所有元素:${arr1[@]}" echo "arr2数组中的所有元素:${arr2[*]}" echo "数组元素的删除:" unset arr1[0] echo "删除后输出arr1中的所有元素:${arr1[@]}" echo "数组的删除:" unset arr2 echo "删除arr2数组后:${arr2[*]}"
### Shell内置命令
#### 内置命令介绍
Shell内置命令,就是由Bash Shell自身提供的命令,而不是文件系统的可执行脚本文件。
使用type来确定一个命令是否是内置命令:
`type 命令`

由此可见,cd是一个Shell内建命令,而ifconfig是一个外部文件,它的位置是/sbin/ifconfig。
通常来说,内置命令会比外部命令执行得更快,执行外部命令时不但会触发磁盘I/O还需要开启一个单独的进程来执行,执行完成后再退出。而执行内置命令相当于调用当前Shell进程的一个函数,还是在当前Shell环境进程内,减少了上下文切换。
Bash Shell中常用的内建命令

#### alias:给命令创建别名
alisa用来给命令创建一个别名。若直接输入该命令且不带任何参数,则列出当前Shell进程中使用了哪些别名。

##### 使用alias命令自定义别名
使用alias命令自定义别名的语法格式为:
`alias 别名='命令'`
设置查看进程的别名
1 2 alias pslist='ps -aux' # 这样使用pslist和输入ps-aux可以达到同样的效果
删除别名
#### echo命令:输出字符串
echo是一个Shell内建命令,用来在终端输出字符串,并在最后**默认加上换行符**。
##### echo不换行输出
echo命令输出结束后默认会换行,如果不希望换行,可以加上`-n`参数。
1 2 # !/bin/bash echo -n "echo不换行输出测试"
##### -e参数
默认情况下,echo不会解析以反斜杠开头的转义字符。比如,\n表示换行,echo默认会将它作为普通字符对待。

#### read命令:读取从键盘输入的数据
read是Shell内置命令,用来从标准输入中读取数据并赋值给变量。如果没有进行重定向,默认就是从键盘读取用户输入的数据;如果进行了重定向,那么可以从文件中读取数据。
read命令的用法为:
`read [-options] [variables]`
options表示选项,如下表所示;variables表示用来存储数据的变量,可以有一个,也可以有多个。
options和variables都是可选的,如果没有提供变量名,那么读取的数据将存放到环境变量REPLY。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 # !/bin/bash # 测试read 内置命令的使用 # 不指定选项及变量 read echo "没有指定变量获取值:$REPLY" read a echo "指定变量获取值:$a" # 添加选项 -p read -p "请输入姓名:" name read -p "请输入年龄:" age echo "姓名:$name, 年龄:$age" # read 参数 -n num# 获取两个字符 read -n 2 -p "获取输入字符串" str echo "读取输入内容:$str" # read 参数 -sread -sp "请输入密码:" password read -sp "请输入确认密码:" repassword echo "密码:$password, 确认密码:$repassword" if [ $password == $repassword ] then echo "密码和确认密码一致" else echo "密码和确认密码不一致" fi # read 参数 -tread -t 5 -p "输入有时间限制,请在5秒内输入:" str echo "输入内容:$str"
read命令支持的选项及options支持的参数


#### exit命令
exit是一个Shell内置命令,用来退出当前Shell进程,并返回一个退出状态;使用`$?`可以接收这个退出状态。
exit命令可以接受一个整数值作为参数,代表退出状态。如果不指定,默认状态值是0。
exit退出状态只能是一个介于0~255之间的整数,其中只有0表示成功,其它值都表示失败。
【示例】Shell脚本文件中使用exit退出
1 2 3 4 # !/bin/bash echo "exit命令示例" exit 3 echo "hello exit命令"
#### declare命令
declare命令的用法如下所示:
`declare [+/-] [aAirfx] [变量名=变量值]`
其中,-表示设置属性,+表示取消属性,aAifⅸ都是具体的选项,它们的含义如下表所示:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # !/bin/bash # 测试 + - # 设置一个整数变量 declare -i age=20 echo "整数变量:$age" age=aaa echo "整数变量age: $age" # 取消变量设置 declare +i age age=bbbb echo "取消age设置后age的值: $age" 设置只读变量 declare -r pi=3.14 echo "只读变量pi的值:$pi" p1=3.3333 echo "只读变量pi的值:$pi"

实现key-value关联数组变量语法
关联数组也称为"键值对(key-value)"数组,键(key)也即字符串形式的数组下标,值(value)也即元素值。
`declare -A 关联数组变量名=([字符串key1]=值1 [字符串key2]=值2 ...)`
declare也可以用于定义普通索引数组,`-a`参数创建普通或索数组 `-A`创建关联数组。
`declare -a 普通数组变量名=(值1 值2 ...)`
`declare -a 普通数组变量名=([0]=值1 [1]=值2 ...)`
获取指定key的值
`${关联数组变量名[key]}`
获取所有值
`${关联数组变量名[*]}`
`${关联数组变量名[@]}`
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # !/bin/bash # 创建普通数组 declare -a arr1=(10 20 30 "abc") declare -a arr2=([0]="baizhan" [2]=a [3]=10 [7]=70) # 获取数组元素 echo "数组arr1中第2个元素:${arr1[1]}" echo "数组arr2中第8个元素:${arr2[7]}" # 获取数组中所有元素 echo "数组arr1中所有的元素:${arr1[*]}" echo "数组arr2中所有的元素:${arr2[@]}" # 创建关联数组 declare -A arr1=(["aa"]=10 ["bb"]=20 ["cc"]=30) # 获取关联数组的值 echo "获取关联数组的值;${arr1["aa"]}" echo "获取关联数组的值:${arr1["cc"]}" # 获取关联数组的所有元素 echo "数组中所有元素的值:${arr1[*]}" # 获取数组的长度 echo "数组的长度:${#arr1[*]}"
### Shell运算符
Shell和其他编程语言一样,支持多种运算符,包括:
- 算数运算符
- 关系运算符
- 逻辑运算符
- 文件测试运算符
原生bash不支持简单的数学运算,需要通过其他命令来实现,如eXpr。
expr是evaluate expressions的缩写,译为"求值表达式”。Shell expr是一个功能强大,并且比较复杂的命令,它除了可以实现整数计算,还可以结合一些选对字符串进行处理,例如计算字符串长度、字符串比较、字符串匹配、字符串提取等。
expr语法:
`expr 算术运算符表达式`
获取计算结果赋值给新变量语法:
注意:这里不是单引号是**反引号**。运算表达式运算符两边必须要有空格。运算不能是小数远算必须是整数运算。
`expr 10 + 10`
#### 算数运算符


注意:条件表达式要放在方括号之间,并且要有空格,例如:`[$a==$b]`是错误的,必须写成`[ $a == $b ]`。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # !/bin/bash # 测试算术运算符 # 输入两个整数 read -p "请输入第一个数:" a read -p "请输入第二个数:" b # 输出输入的值 echo "a:$a, b:$b" result=`expr $a + $b` echo "加法的结果:$result" result=`expr $a - $b` echo "减法的结果:$result" result=`expr $a \* $b` echo "乘法的结果:$result" result=`expr $a / $b` echo "除法的结果:$result" result=`expr $a % $b` echo "取余的结果:$result"
#### 比较运算符
##### 整数处比较运算符
假定变量a为10,变量b为20:


##### 字符串比较运算符
字符串比较运算符可以比较2个变量,变量的类型可以为**数字(整数,小数)与字符串**。
下表列出了常用的字符串运算符,假定变量a为"abc",变量b为"efg"。
字符串比较可以使用`[[]]`和`[]`2种方式。


字符串比较没有`<=`可以通过`[[ "a" < "b" || "a" == "b"]]`
`[[]]`和`[]`的区别
由于(())只能比较整数,不能比较小数和字符串所以不建议使用。
区别1:`[]`会产生单词分隔现象,`[[]]`不会产生单词分隔

区别2:`[]`需要对`>`和`<`进行转义

#### 布尔运算符
下表列出了常用的布尔运算符,假定变量a为10,变量b为20:


:warning:注意:布尔运算符必须放在`[]`或与test命令配合使用才有效

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 # !/bin/bash a=10 b=20 # 布尔运算符使用到if 条件中 if [ ! $a \> $b ] then echo "a变量的值小于等于b" else echo "a变量的值大于b" fi str="abc" if [ $str -o 1 == 2 ] then echo "条件成立" else echo "条件不成立" fi if [ $str -a 1 == 2 ] then echo "条件成立" else echo "条件不成立" fi
#### 逻辑运算符
假定变量a为10,变量b为20:


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # !/bin/bash a=100 b=200 # 布尔运算符 [] !-o -a if [ $a \< $b -o 10 == 100 ] then echo"布尔运算符:条件成立” else echo"布尔运算符:条件不成立" fi # 逻辑运算符[[]] if [[ $a -lt $b || 10 == 100 ]] then echo"逻辑运算符条件成立" else echo"逻辑运算符条件不成立" fi
#### 文件测试运算符
文件测试运算符用于检查文件,如检查文件是否存在、是否可读、是否可执行、是否为空、是否可写、是否是目录、是否是普通文件。
属性检测描述如下:



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 # !/bin/bash # 文件测试运算符 file=/root/test_shell/test_suanshu.sh if [ -e $file ] then echo "文件存在" else echo "文件不存在" fi # 判断文件是普通文件吗 if [ -f $file ] then echo "文件是普通文件" else echo "文件不是普通文件" fi # 判断文件是目录吗 if [ -d $file ] then echo "文件是目录" else echo "文件不是目录" fi # 判断文件是否为空 if [ -s $file ] then echo "文件不为空" else echo "文件为空" fi # 判断文件是否可读 可写 可执行 if [-r $file ] then echo "文件可读" else echo "文件不可读” fi if [ -w $file ] then echo "文件可写" else echo "文件不可写" fi if [ -x $file ] then echo "文件可执行" else echo "文件不可执行" fi
### 计算命令
要想让数学计算发挥作用,必须使用数学计算命令,shell中常用的数学计算命令如下表所示。

#### expr命令
##### expr用于求表达式的值
语法:
`expr 算术运算符表达式`
【示例】expr求表达式的值

【示例】expr表达式的值赋给变量

##### expr在字符串中的使用
**计算字符串的长度**
`expr length 字符串`
【示例】计算字符串的长度

**截取字符串**
`expr substr 字符串 start len`
start:截取字符串的起始位置,从1开始
len:截取字符串的个数

**获取第一个字符在字符串中出现的位置**
`expr index 被查找字符串 需要查找的字符`
【示例】获取第一个字符在字符串中出现的位置

**正则表达式匹配语法1**
`expr match 字符串 正则表达式`
返回值为符合匹配字符串的长度,否则返回为0
【示例】正则表达式匹配语法1

**正则表达式匹配语法2**
`expr 字符串 : 正则表达式`
返回值为符合匹配字符串的长度,否则返回为0
【示例】正则表达式匹配语法2

#### (())命令
能够使用`(())`进行**整数**的数学运算。将数学运算表达式放到`((`和`))`之间,可以使用`$`获取`(())`表达式命令的结果,这和使用`$`获得变量值是一样的。
语法:
`((表达式))`
用法:



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # !/bin/bash # (())命令的使用 ((a=10+20)) ((b=a-10)) ((c=a+b))I echo "a=$a,b=$b,c=$c" a=$((10+20)) b=$((a-10)) c=$((a+b)) echo "a=$a,b=$b,c=$c" if ((a>10 && a==c)) then echo "a>10 && a==c" else echo "不成立" fi echo $((100+100)) ((a=10+20,b=a-10,c=a+b)) echo "a=$a,b=$b,c=$c"
==注意:符号之间有无空格都可以,((a = 1 + 2))等价于((a=1+2))==
#### let命令
能够使用let进行整数的数学运算赋值。let命令和双小括`(())`在数字计算方面功能一样,但是没有`(())`功能强大,**let只能用于赋值计算,不能直接输出,不可以条件判断。**
语法:
`let 赋值表达式`
多个表达式赋值语法:
`let 变量名1=值1 变量名2=值2 …`
1 2 3 4 5 6 7 8 9 10 11 # !/bin/bash # let 命令的使用let a=10+20 let b=a-10 let c=a+b echo "a=$a,b=$b,c=$c" echo"a=${a},b=${b},c=${c}" # let 命令用于多个赋值表达式let a=10+20 b=a-10 c=a+b echo "a=$a,b=$b,c=$c"
#### $[]命令
和`(())`和Iet命令类似,`$[]`也只能进行整数运算,但是只能对==单个表达式==的计算求值与输出。
语法:
`$[表达式]`
1. `$[]`会对表达式进行计算,并取得计算结果
2. 表达式内部不可以赋值给变量
1 2 3 4 5 # !/bin/bash a=$[10+20] b=$[a-10] c=$[a+b] echo "a=$a,b=$b,c=$c"
**执行整数表达式命令总结:**

#### bc命令
Bash shell内置了对整数运算的支持,但是并不支持浮点运算,而linux bc命令可以很方便的进行**浮点运算**。bc命令是Liux简单的计算器,能进行进制转换与计算。能转换的进制包括十六进制、十进制、八进制、二进制等。可以使用的运算符号包括(+)加法、(-)减法、(*)乘法、(/)除法、(^)指数、(%)余数等。
语法:
`bc [options] [参数]`
options选项

默认使用bc命令后回车会有很多欢迎信息,可以使用`bc -q`回车后不会有欢迎信息。

##### 基本使用

【示例】**bc命令执行计算任务的文件**
创建一个文件test task.txt
1 2 3 108*67+123456 58+2008*11 3.14*43+187.23
执行任务文件计算每行表达式的值
`bc -q test_task.txt`
##### 内置变量的使用



##### 内置数学函数的使用
内置数学函数


【示例】bc中内置的数学函数的使用
使用内置函数时必须使用`bc -ql`

##### 非互动式的运算
**直接进行bc的表达式计算输出**
`echo "expression" | bc [options]`
expression:表达式必须符合bc命令要求的公式
表达式里面可以引用shell变量
例如:shell变量a=2在表达式里面引用的语法:$a
【示例】bc中非互动式的运算


##### 将bc计算的结果赋值给shell变量
语法格式:
#第一种方式
1 var name=`echo "expression" | bc [options]`
#第二种方式
1 var name=$(echo "expression" | bc [options])
`$()`与``功能一样,都是执行里面的命令
区别:
``是所有linux系统支持的方式,兼容性较好,但是容易与引号产生混淆。
`$()`不是所有linux系统都支持的方式。兼容性较差,但是不容易产生混淆。
【示例】将bc计算的结果赋值给shell变量

##### 非互动式的输入重定向运算
将计算表达式输出给bc去执行,特点类似于文件中输入,可以输入多行表达式。更加清晰。
语法:
#第一种方式
1 2 3 4 5 6 var name=`bc [options] <<EOF 第一行表达式 第二行表达式 ... EOF `
#第二种方式
1 2 3 4 5 6 var name=$(bc [options] <<EOF 第一行表达式 第二行表达式 ... EOF )
var name这里Shell变量的名字
bc执行bc的命令
EOF..EOF输入流的多行表达式
含义:将EOF中间多行表达式输入给到bc去执行,将bc执行的结果赋值shel变量
【示例】Shell中非互动式的输入重定向运算

### 流程控制语句
#### 条件if语句
##### if语句语法格式
1 2 3 4 5 6 7 if condition then command1 command2 ... commandN fi
写成一行(适用于终端命令提示符):
`if 条件;then 命令;fi`
【示例】判断num的值是否是10
1 2 3 4 5 6 7 8 # !/bin/bash # 测试if 单分支 # 键盘输入一个数num read -p "请输入一个数:" num if ((num==10)) then echo"您输入的数是10" fi
##### if else语句语法格式
1 2 3 4 5 6 7 8 9 if condition then commadd1 command2 ... commandN else command fi
写成一行(适用于终端命令提示符):
`if 条件;then 命令;else 命令;fi`
【示例】输入年龄判断是否成人
1 2 3 4 5 6 7 8 9 # !/bin/bash # 测试if else read -p"请输入年龄:"age if ((age>=18)) then echo "成年" else echo "未成年" fi
##### if else-if else语法格式
1 2 3 4 5 6 7 8 9 if condition1 then command1 elif codition2 then command2 else commandN fi
【示例】输入成绩判断成绩等级
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # !/bin/bash # 测试if elif else 多分支结构 read -p "请输入成绩:" score if ((score>=90)) then echo "成绩等级为A" elif ((score>=80)) then echo "成绩等级为B" elif ((score>=70)) then echo "成绩等级为C” elif ((score>=60)) then echo "成绩及格" else echo "成绩不及格" fi
【示例】根据输入的值判断是周几。如输入1输出”周一“
1 2 3 4 5 6 7 8 9 # !/bin/bash read -p"请输入一个数(1-7):" num if [[ $num == 1 ]] then echo "周一" elif [[ $num == 2 ]] then echo "周二" fi
##### 选择嵌套
语法格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 if [ condition1 ];then command1 if [ condition2 ];then command2 fi else if [ condition3 ];then command3 elif [ condition4 ];then command4 else command5 fi fi
【示例】输入成绩输出成绩的等级
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 # !/bin/bash # if 条件语句嵌套read -p "请输入成绩:" score if ((score>0 && score<=100)) then echo "输入的成绩是正确的" if ((score>=90)) then echo "成绩的等级为A" elif ((score>=80)) then echo "成绩的等级为B" elif ((score>=70)】 then echo "成绩的等级为C" elif ((score>=60)】 then echo "及格" else echo "不及格" fi else echo "偷入的成绩不正确” fi
#### 内置命令test
Shell中test命令用于检查某个条件是否成立,它可以进行数值、字符串和文件三个方面的测试。功能和一样。
##### 整数比较测试
整数比较语法
1 2 3 if test 数字1 options 数字2 then fi
options具体如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # !/bin/bash # test 命令检查整数num1=100 num2=200 if test $numl -lt $num2 then echo "num1小于num2" else echo "num1不小于num2" fi num3=200 if test $num2 -eq $num3 then echo "num2和num3相等" fi # -a -o if test $num1 -lt $num2 -a $num2 -eq $num3 then echo "两个条件成立" else echo "两个条件不成立" fi
##### 字符串比较测试


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 # !/bin/bash # test 命令检查字符串str1="hello" if test -z $str1 then echo "str1为空" else echo "str1不为空" fi if test $str1 then echo "str1不为空" else echo "str1为空" fi str2="world" if test $strl = $str2 then echo "str1和str2相等" else echo "不相等" fi # 多条件 if test $strl -o 1 -eq 1 then echo "条件成立" fi if test $strl -a 10 -eq 1 then echo "条件成立" else echo "条件不成立" fi
##### 文件测试

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 # !/bin/bash # test 检查文件file="/root/test_shell/test_test1.sh" if test -e $file then echo "文件存在" else echo "文件不存在” fi if test -r $file then echo "文件可读” fi if test -w $file then echo "文件可写" fi if test -s $file then echo "文件不为空" fi if test -d $sfile then echo "文件是目录" else echo "文件不是目录" fi
test命令经常与`-a`和`-o`一起使用,`&&`和`||`只能使用到`[]`中
【示例】if中有多条件时候,必须都满足才会执行
根据提示输入文件全名和输入写入的数据。判断文件是否有可写权限和输入的数据长度不为0,满足以上2个条件将用户的数据写入到指定的文件中去。
1 2 3 4 5 6 7 8 9 10 11 # !/bin/bash read -p "请输入文件名:" filename read -p "请输入写入的内容:" data echo "文件名:$filename,内容:$data" if test -w $filename -a -n $data then echo $data > $filename echo "写入内容成功" else echo "写入内容失败" fi
#### case语句
`case...esac`为多选择语句,与其他语言中的switch...case语句类似,是一种多分枝选择结构,每个case分支用右圆括号`)`开始,用两个分`;;`表示执行结束,跳出整个case...esac语句,esac(就是case反过来)作为结束标记。
可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。
`case...esac`语法格式如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 case 值 in 模式1) command1 command2 ... commandN ;; 模式2) command1 command2 ... commandN ;; esac
case工作方式如上所示,取值后面必须为单词in,每一模式必须以右括号结束。取值可以为变量或常数,匹配发现取值符合某一模式后,其间所有命令开始执行直至`;;`。
取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号`*`捕获该值,再执行后面的命令。
case、in和esac都是Shell关键字,esac就是case的反写在这里代表结束case。
匹配模式:可以是一个数字、一个字符串,甚至是一个简单正则表达式。
简单正则表达式支持如下通配符:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 # !/bin/bash # case 多分支选择结构read -p "请输入一个(0-7)之间的数:" num case $num in 1) echo "周一" ;; 2) echo "周二" ;; 3) echo "周三" ;; 4) echo "周四" ;; 5) echo "周五" ;; 6) echo "周六" ;; 0|7) echo "周日" ;; *) echo "输入有误" ;; esac
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # !/bin/bash # case 多分支结构case $1 in start | S) echo "启动成功" ;; stop | T) echo "停止成功" ;; restart | R) echo "重新启动成功" ;; *) echo "输入有误" ;; esac

#### while语句
##### while循环
while循环用于不断执行一系列命令,也用于从输入文件中读取数据。其语法格式为:
1 2 3 4 while condition do command done
1 2 3 4 5 6 7 8 9 10 # !/bin/bash # while 循环# 键盘输入一个数 read -p "请输入一个整数:" num i=1 while ((i<=num)) do echo"当前i的值:$i" let i++ done
1 2 3 4 5 6 7 8 9 10 11 12 # !/bin/bash # 使用whi1e循环求1-100的和 i=1 sum=0 while ((i<=100)) do sum=$((sum+i)) # sum =`expr $sum + $i ` # sum =$(($sum +$i )) let i++ done echo "sum: $sum"
##### 无限循环
无限循环语法格式:
或
1 2 3 4 while true do command done


##### 跳出循环
在循环过程中,有时候需要在未达到循环结束条件时强制跳出循环,Shell使用两个命令来实现该功能:break和continue
**break命令**
break命令允许跳出当前整个循环。
【示例】break命令退出当前循环,脚本进入死循环直至用户输入数字大于5。要跳出这个循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # !/bin/bash # 退出循环break 的使用 while true do read -p "请输入一个整数:" num case $num in 1|2|3|4|5) echo "您输入的数:$num" ;; *) echo "您输入的数不是1 2 3 4 5,退出循环" break ;; esac done
**continue命令**
continue命令允许跳出本次循环。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 # !/bin/bash # 测试退出循坏continue while do read -p "请输入一个数:" num if ((num==1 || num==2 || num==3 || num==4 || num==5)) then echo "您输入的数是:$num" else echo "您输入的数不是1 2 3 4 5" continue echo"continue退出本次循环" fi done
#### until语句
until循环执行一系列命令直至条件为true时停止。until循环与while循环在处理方式上刚好相反。
一般while循环优于until循环,但在某些时候一也只是极少数情况下,until循环更加有用。
until语法格式:
1 2 3 4 until condition do command done
condition一般为条件表达式,如果返回值为false,则继续执行循环体内的语句,否则跳出循环。
【示例】使用until命令来输出0~9的数字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # !/bin/bash # 测试until循坏 # 输出0-9的数 i=0 # until [[ ! $i -le 9 ]] until ((i>9)) do echo "当前i的值:$i" let i++ done # 计算1-100之间的和 i=1 sum=0 until ((i>100)) do sum=$((i+sum)) let i++ done echo "1-100的和:$sum"
#### for语句
##### 循环第一种方式
与其他编程语言类似,Shell支持for循环。
for循环一般格式为:
1 2 3 4 5 6 for var in item1 item2 ... itemN do command1 command2 commandN done
写成一行:
1 for var in item1 item2 ... itemN;do command1;command2... done;
【示例】for循环顺序输出当前列表中的数字
1 2 3 4 5 6 7 8 9 10 11 # !/bin/bash # for 循环 for in for i in 1 2 3 10 20 30 do echo "当前变量的值:$i" done for v in hello bai d com baizhai do echo "当前变量的值:$v" done
##### 循环第二种方式
语法:
1 2 3 4 for var in {start..end} do 命令 done
start:循环范围的起始值必须为整数
end:循环范围的结束值,必须为整数
1 2 3 4 5 6 7 8 9 10 11 12 13 # !/bin/bash # 输出1-10的整数 for i in {1..10} do echo "当前整数:$i" done sum=0 for i in {1..100} do sum=$((sum+i)) done echo "1-100的和:$sum"
##### 循环第三种方式
语法:
1 2 3 4 for((i=start;i<=end;i++)) do 命令 done
一行写法:
1 for(i=start;i<=end;i++);do 命令;done
1 2 3 4 5 6 # !/bin/bash # 使用for 循环输出10-20之间的数 for((i=10;i<=20;i++)) do echo "当前i的值:$i" done
##### for循环的无限循环
for循环的无限循环语法:
`for((;;));do 命令;done`
1 2 3 4 5 6 7 8 9 10 11 12 13 14 # !/bin/bash # for 无限循环i=1 for((;;)) do if((i==5)) then echo "i等于5退出循环" break else echo "当前i的值:$i" let i++ fi done
#### select语句
select in循环用于增强交互性,它可以显示出带编号的菜单,用于输入不同的编号就可以选择不同的菜单,并执行不同的功能,select in是Shell独有的一种循环,非常适合终端这样的交互场景,其它语言没有。
语法格式如下:
1 2 3 4 select var in 菜单1 菜单2 ... do 命令 done
注意:select是无限循环(死循环),输入空值,或者输入的值无效,都不会结束循环,只有遇到break语句,或者按下Ctrl+D组合键才能结束循环。
执行命令中终端输出`#?`代表可以输入选择的菜单编号
【示例】select in的使用
1 2 3 4 5 6 7 8 # !/bin/bash # 测试select语句的使用 echo "一年四个季节,您最喜欢哪个季节?" select d in "春大" "夏天" "秋大" "冬天" do echo "您最喜欢的季节是:$d" break done

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 # !/bin/bash # select语句与case 一起使用 echo "您最喜欢的老师是哪位?" select t in 张老师 李老师 王老师 赵老师 do case $t in "张老师") echo "您最喜欢的老师是张老师" break ;; "李老师") echo "您最喜欢的老师是李老师" break ;; "赵老师")I echo "您最喜欢的老师是赵老师" break ;; "王老师") echo "您最喜欢的老师是王老师" break ;; esac done

### Shell函数
Shell函数和其他编程语言一样,函数是由若干条Shell命令组成的语句块,实现Shell脚本代码重用和模块化编程。
#### 系统函数
##### basename
basename返回完整路径最后/的部分,常用于获取文件名,基本语法如下:
`basename [pathname] [suffix]`
suffix为后缀,如果suffix被指定了,basename会将pathname或string中的suffix去掉。
【示例】basename的使用

【示例】basename的使用(写入到脚本文件)
1 2 3 4 5 6 # !/bin/bash # 系统函数basename filename1=`basename /root/test_shell/test_while.sh` filename2=$(basename /root/test_shell/test_while.sh .sh) echo "filenamel:$filename1" echo "filename2:$filename2"
##### dirname
dirname返回完整路径最后V的前面的部分,常用于返回路径部分。
dirname文件绝对路径(功能描述:从给定的包含绝对路径的文件名中去除文件名(非目录的部分),然后返回剩下的路径(目录的部分))
【示例】dirname的使用

【示例】dirname的使用(写到脚本中)
1 2 3 4 5 6 # !/bin/bash # dirname 系统函数filename=`basename /root/test_shell/test_while.sh` mydire=$(dirname /root/test_shell/test_while.sh) echo "文件名:$filename" echo "文件路径:$mydire"
#### 自定义函数
##### 函数定义
shell中函数的定义格式如下:
1 2 3 4 5 [ function ] funname [()] { action; [return int;] }
说明:
1. 可以带function fun()定义,也可以直接fun()定义,不带任何参数。
2. 参数返回,可以显示加:return返回,如果不加,将以最后一条命令运行结果,作为返回值。return后跟数值n(0-255)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # !/bin/bash # 自定义函数 function test_fun1(){ echo "自定义函数fun1" } # 调用函数之前必须先定义好函数 # test fun2test fun2(){ echo "自定义函数fun2" } # 调用函数 test_fun1 test_fun2
【示例】函数示例(有返回值)
1 2 3 4 5 6 7 8 9 10 11 12 # !/bin/bash # 定义函数,有返回值 test_add(){ # 键盘输入两个整数 read -p "请输入第一个整数:" num1 read -p "请输入第二个整数:" num2 return $((num1+num2)) # 调用函数 test_add # 获取函数的返回值 echo "函数的返回值:$?"
函数返回值在调用该函数后通过`$?`来获得。
注意:**所有函数在使用前必须定义**。这意味着必须将函数放在脚本开始部分,直至shell解释器首次发现它时,才可以使用。调用函数仅使用其函数名即可。
##### 函数参数
在Shell中,调用函数时可以向其传递参数。在函数体内部,通过`$n`的形式来获取参数的值,例如,`$1`表示第一个参数,`$2`表示第二个参数...
注意,`$10`不能获取第十个参数,获取第十个参数需要`${10}`。当n>=10时,需要使用`${n}`来获取参数。
【示例】函数参数的使用
1 2 3 4 5 6 7 8 9 10 11 # !/bin/bash # 定义函数传递函数参数 test_param(){ echo "第一个参数:$1" echo "第二个参数:$2" echo "第三个参数:$3" echo "第10个参数:${10}" echo "第11个参数:${11}" # 调用函数 test_param 1 2 3 4 5 6 7 8 9 100 101 102
【示例】定义函数绘制图像
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 # !/bin/bash # 定义函数及for 循环综合练习 # 输出一个矩形 echo "输出一个矩形" test_fun1(){ for i in {1..5} do echo "***" done } test_fun1 echo '输出一个矩形2' test_fun2(){ for((i=1;i<=6;i++)) do for((j=1;j<=4;j++)) do echo -n "*" done echo # 输出换行 done } test_fun2 echo "输出直角三角形” test_fun3(){ for((i=1;i<=5;i++)) do for((j=1;j<=$i;j++)) do echo -n "*" done echo done } test_fun3

##### Shell程序与函数的区别
函数和Shell程序比较相似,区别在于:
Shell程序(内置命令和外部脚本文件),外部脚本文件是在子Shell中运行,会开启独立的进程运行。
Shell函数在当前Shell的进程中运行。
【示例】Shel程序与函数的区别
1 2 3 4 5 6 # !/bin/bash test_fun(){ echo "函数中输出:进程ID$$" } test_fun echo "脚本文件中:进程ID$$"

### Shell重定向输入输出
#### 概念
##### 标准输入
从键盘读取用户输入的数据,然后再把数据拿到Shell程序中使用。
##### 标准输出
Shell程序产生的数据,这些数据一般都是呈现到显示器上供用户浏览查看
##### 输入输出重定向
输入方向就是数据从哪里流向程序。数据默认从键盘流向程序,如果改变了它的方向,数据就从其它地方流入,这就是输入重定向。
输出方向就是数据从程序流向哪里。数据默认从程序流向显示器,如果改变了它的方向,数据就流向其它地方,这就是输出重定向。
#### 文件描述符
linux命令默认从标准输入设备(stdin)获取输入,将结果输出到标准输出设备(stdout)显示。一般情况下,标准输入设备就是键盘,标准输出设备就是终端,即显示器。
在linux shell执行命令时,每个进程都和三个打开的文件相联系,并使用文件描述符来引用这些文件。由于文件描述符不容易记忆,shell同时也给出了相应的文件名。

#### 重定向命令列表

##### 输出重定向



##### 输入重定向
wC命令可以用来对文本进行统计,包括单词个数、行数、字节数。
wc语法格式:
`wc [options] [文件名]`
options有如下:


【示例】读取文件每行内容
1 2 3 4 5 6 7 8 9 # !/bin/bash # 输入重定间 # 读取文件内容 r=1 while read m do echo"第$r行,内容是:$m" let r++ done < log.txt
【示例】标记位读取内容

### 文本处理工具
#### grep文本搜索
grep是一种强大的文本搜索工具,用于根据关键字进行行过滤,并把匹配的行打印出来。
grep语法格式:
`grep [选项] '关键字' 文件名`
它在一个或多个文件中搜索满足模式的文本行。
常用的grep选项:









#### cut按列切分文本
cut译为“剪切、切割”,是一个强大文本处理工具,它可以将文本按列进行划分的文本处理。cut命令逐行读入文本,然后按列划分字段并进行提取、输出等操作。
语法格式:
`cut [options] 文件名`
options参数说明

**提取范围说明**

【示例】cut的使用
准备test_cut.xt文件内容

【示例】cut截取列数据


【示例】cut按字符提取



【示例】cut的切割获取指定单词

【示例】cut的切割bash进程的PID号

【示例】cut的切割当前服务器的IP

#### sed文本编辑器
sed是Liux下一款功能强大的非交互流式文本编辑器,可以对文本文件进行增、删改、查等操作,支持按行、按字段、按正则匹配文本内容,灵活方便,特别适合于大文件的编辑。
sed工作原理:sed会读取每一行数据到模式空间中,判断当前行是否符合模式心配要求,符合要求就会执行sed程序命令,否则不会执行sed程序命令,如果不写四配模式,那么每一行都会执行sed程序命令。
sed的使用语法:
`sed [选项参数] [模式匹配 | sed程序命令] [文件名]`
sed的常用选项:


##### 【示例】向文件中添加或插入行
1.准备test_sed.txt内容
2.`sed '3aworld' test_sed.txt` #向第三行后面添加world,3表示行号

注意:预览可以看到是添加了,但实际没有添加到文件内容。想要真是的添加到文件,需要加选项 `-i`。




##### 【示例】更改文件中指定的行


##### 【示例】删除文件中的行


2.删除3~5之外的所有行

3.删除从匹配abc的行到最后一行

4.删除空行

5.删除不匹配hello或abc的行,`/hello\|abc/`表示匹配hello或abc,`!`表示取反

6.删除`1~3`行中,匹配内容hello的行,1,3表示匹配`1~3`行,`{/hello/d}`表示删除匹配hello的行

##### 【示例】替换文件中的内容
1.将文件中的a替换为123,默认只替换每行第一个123



4.将每行中所有匹配的a替换为123,并将替换后的内容写入test_sed2.txt


5.匹配有#号的行,替换匹配行中逗号后的所有内容为空`(,.*)`表示逗号后的所有内容

6.替换每行中的最后两个字符为空,每个点代表一个字符,`$`表示匹配末尾`(...$)`表示匹配最后两个字符

7.在test_sed.txt文件的每一行后面加上"hahha"字段

##### 【示例】打印文件中的行
1.打印文件中的第三行内容

2.从第一行开始,每隔两行打印一行,波浪号后面的2表示步长

3.打印文件的最后一行

4.打印1-3行

5.打印匹配的行

##### 【示例】打印文件的行号
1.打印test sed.txt文件最后一行的行号

2.打印匹配abc的行的行号

3.打印空行行号

##### 【示例】从文件中读取内容
1.将文件test_sed3.txt中的内容,读入test_sed4.txt中,会在test_sed4.txt中的**每一行**后都读入test_sed3.txt的内容

2.在test_sed.3.txt的第3行之后插入文件test_sed4.txt的内容(可用于向文件中插入内容)

3.在匹配456的行之后插入文件test_sed4.txt的内容,如果test_sed3.txt中有多行匹配456则在每一行之后都会插入

4.在test_sed3.txt的最后一行插入test_sed4.txt的内容

##### 【示例】向文件中写入内容
1.将test_sed3.txt文件的内容写入test_sed4.txt文件,如果test_sed3.txt文件不存在则创建,如果test_sed.4.txt存在则覆盖之前的内容

2.将文件test_sed3.txt中的第2行内容写入到文件test_sed4.txt

3.将test_sed3.txt的第2行和最后一行内容写入test_sed4.txt

-e: 它告诉sed将下一个参数解释为一个sed指令,只有当命令行上给出多个sed指令时才需要使用-e选项
4.将test_sed3.txt的第2行和最后一行内容分别写入test_sed4.txt和test_sed5.txt中

5.将test_sed3.txt中匹配789或123的行的内容,写入到test_sed4.txt中

6.将test_sed.3.txt中从匹配123的行到最后行的内容,写入到test_sed.4.txt中
`,$`:到最后一行

7.将test_sed3.txt中从匹配456的行及其后2行的内容,写入到test_sed4.txt中

#### awk文本分析工具
##### awk概述
awk是一种强大的文本分析工具,主要用于在linux/uniⅸ下对文本和数据进行处理。对数据进行分析、统计并生成报表,比如网站的访问量,访问的IP量等等。
awk是种编程语言,awk可以定义变量、运算符,使用流程控制语句进行深度加工与分析。
awk其名称得自于它的创始人Alfred Aho、Peter Weinberger和Brian Kernighan姓氏的首个字母。
awk的处理文本和数据的方式:把文件逐行读入,以空格为默认分隔符将每行切片。切片的部分再进行各种分析处理。
##### awk基本使用
使用方法:
`awk 选项 '命令部分' 文件名`
特别说明:引用shell变量需用双引号引起
常用命令选项

AWK内置变量


【示例】awk匹配内容整行输出,默认每行空格切割数据,并将这行赋给内部变量$0

【示例】awk匹配以root开头的行

【示例】awk使用一行作为输入,默认每行空格切割数据,并将这行赋给内部变量$0


##### 格式化输出print和printf
print函数:类似echo,它是**换行输出**
printf函数:类似echo-n,它**不换行输出**,可以使用%s、%d进行占位。其中%s表示字符类型,%d数值类型。
`-`:表示左对齐,默认是右对齐
例如:`%-15s` 表示所占15字符,使用左对齐方式显示。
【示例】print的使用

【示例】printf占位的使用



【示例】print打印文件每行属性信息
统计passwd文件名,每行的行号,每行的列数,对应的完整行内容


【示例】打印第三行信息

##### awk中BEGIN...END使用
BEGIN:表示在程序开始前执行
END:表示所有文件处理完后执行
用法:`'BEGIN{开始处理之前};{处理中};END{处理结束后}'`
【示例】添加开始与结束内容



##### awk变量定义
【示例】-v定义变量

##### awk中流程控制语句

1. if语句语法格式
`{ if(表达式) {语句1;语句2;...} }`
准备test_awk.txt文件


2. if else的语法格式
`{if(表达式) {语句;语句;...} else{语句;语句;...}}
【示例】awk中使用if...else
if else if else if的语法格式
1 2 3 4 {if(表达式1){语句;语句;...} else if(表达式2){语句;语句; ...} else if(表达式3){语句;语句; ...} else{语句;语句; ...}}
awk中循环语句的使用
【示例】使用循环拼接字符串
【示例】使用循环计算每行的和
【示例】循环中使用break
【示例】操指定数字运算
【示例】切割ip
【示例】显示空行行号
sort sort命令以行为单位对文本进行排序。sort将文件的每一行作为一个单位,相互比较,比较原则是从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出。
【示例】sort的使用
【示例】sort的-u
选项 在输出行中去除重复行。
【示例】sort的-r
选项 sort默认的排序方式是升序,如果想改成降序,就加个-r
就搞定了。
【示例】sort的-o选项 由于sort默认是把结果输出到标准输出,所以需要用重定向才能将结果写入文件,形如 sort filename > newfile
,
但是,如果你想把排序结果输出到原文件中,用重定向可就不行了。
【示例】sort的-n
选项 对数字排序,会出现一种现象,如10比2小的情况。出现这种情况是由于排序程序将这些数字按字符来排序了,排序程序会先比较1和2,显然1小,所以就将10放在2前面。这也是sort的一贯作风。
如果想改变这种现状,就要使用-n
选项,“要以数值来排序”!
【示例】sort的-t
选项和-k
选项 -t
选项,后面可以设定间隔符。
-k
选项,分割后用来指定列数了。
这个文件有三列,列与列之间用冒号隔开了,第一列表示水果类型,第二列表示水果数量,第三列表示水果价格。
现在想以水果数量来排序,也就是以第二列来排序,如何利用sort实现?
tee tee命令作用把输出的一个副本输送到标准输出,另一个副本拷贝到相应的文件中。如果希望在看到输出的同时,也将其存入一个文件,那么这个命令再合适不过了。
它的使用语法格式:
tee [-a] files
其中,-a表示追加到文件末尾。
当执行某些命令或脚本时,如果希望把输出保存下来,tee命令非常方便。
>/dev/null
:不显示在屏幕上
案例 批量修改文件 将某目录下.txt文件全部修改为.bat。
1.批量创建文件
mkdir test_filedir
touch test_filedir/file{1...10).txt
2.重命名文件语法
rename 旧文件名 新文件名 旧文件所在位置
注意:旧文件所在位置后面加/*
例如:/root/test filedir/*
s
1 2 3 4 5 6 7 8 9 10 11 # !/bin/bash # 批量修改文件 # 获取所有要修收的文件 filenames=$(ls /root/test_shell/test_filedir | grep 'txt') for fname in $filenames do echo"文件名:"$fname newname=$(basename $fname .txt)".bat" echo "新文件名:"$newname rename $fname $newname /root/test_shell/test_filedir/* done
批量创建用户 添加用户的命令
useradd 用户名
给用户设置默认密码
echo "123456" | passwd-stdin 用户名
【示例】批量添加用户
1 2 3 4 5 6 7 8 9 10 11 12 13 # !/bin/bash # 批量创建用户 # 获取文件中要添加的所有用户名 users=$(cat /root/test_shell/test_adduser.txt) for u in $users do # echo $u # 添加用户 useradd $u # 初始化密码 echo "123456" | passwd --stdin $u &>/dev/null [ $? -eq 0 ] && echo "添加用户"$u"初始化密吗成功” done
计算linux系统所有进程占用内存大小的和 1.查看进程内存大小
ps-aux
2.可以看到有多列,RSS这列表示所占内存大小。提取RSS这列并去掉RSS这行
ps -aux | awk '{print $6}' | grep -v 'RSS'
3.统计进程大小之和
1 2 3 4 5 6 7 8 9 10 # !/bin/bash # 统计linux系统中所有进程所占内存大小之和 ps_aux=$(ps -aux | awk '{print $6}' | grep -v 'RSS') sum=0 for n in $ps_aux do sum=$[ $sum + $n ] done sum=$[ $sum / 1024 ] echo "所占内存:$sum""M"
【示例】统计系统中各种类型的shell并按降序排序显示 在awk中数组叫做关联数组(associative arrays)。awk中的数组不必提前声明,也不必声明大小 。数组元素用0或空字符串来初始化,这根据上下文而定。
1.awk中的数组赋值并获取
2.统计系统中各种类型的shell并按降序排序显示