shell脚本
打印当前系统环境使用的shell解析器类型
echo $SHELL
一、shell脚本文件编写规范
1.1脚本文件后缀名规范
shell脚本文件就是一个文本文件,后缀名使用.sh
结尾
1.2首行格式规范
#!/bin/bash
含义:设置当前shell脚本文件才用bash解析器运行
1.3shell脚本文件的3种执行方式
-
sh解析器执行方式
语法:
sh 脚本文件
介绍:利用sh命令执行脚本文件,本质就是使用shell解析器运行脚本文件
-
bash解析器执行方式
语法:
bash 脚本文件
介绍:利用bash命令执行脚本文件,本质就是使用shell解析器运行脚本文件
-
仅路径执行方式
语法:
./脚本文件
介绍:执行当前目录下的脚本文件
注意:脚本文件自己执行需要具有可执行权限,否则无法执行
chmod +x 脚本文件路径
3种方式的区别
sh或bash执行脚本文件方式是直接使用shell解析器运行脚本文件,不需要可执行权限。
仅路径方式是执行脚本文件自己,需要可执行权限。
二、自定义变量
2.1自定义局部变量
定义在一个脚本文件中的变量,只能在这个脚本文件中使用。
var_name=value
变量定义规则
1.变量名可以有字母,数字和下划线组成,不能以数字开头
2.等号两侧不能有空格
3.在bash环境中,变量的默认类型都是字符串类型,无法直接进行数值运算
4.变量的值如果为空,必须使用双引号括起来
5.不能使用shell的关键字作为变量名称
查询变量值语法
# 语法1:直接使用变量名查询
$var_name
# 语法2:使用花括号
${var_name}
#区别 花括号方式适合拼接字符串
变量删除
unset var_name
2.2自定义常量
变量设置值以后不可以修改的变量叫常量,也叫只读变量
readonly var_name
2.3自定义全局变量
在当前脚本文件中定义全局变量,这个全局变量可以在当前shell环境与子shell环境中都可以使用
export var_name1 var_name2
父子shell环境
有两个shell脚本文件A.sh和B.sh
如果在A.sh脚本文件中执行了B.sh脚本文件,那么A.sh就是父shell环境,B.sh就是子shell环境
2.4特殊变量
- $n变量
$n
# 用于接收脚本文件执行时传入的参数
$0 # 用于获取当前脚本文件名称
$1~9 # 代表获取第一个输入参数到第九个输入参数
${数字} # 第10个以上的输入参数获取参数格式。
执行脚本文件传入参数
sh 脚本文件 输入参数1 输入参数2...
2.$#变量
# 获取所有输入参数的个数
3.$* 变量和 $@变量
$*
$@
# 获取所有输入参数,用于以后输出所有参数
$*
与$@
区别
1.不适用双引号括起来,功能一样
∗ 和 *和 ∗和@获取所有输入参数,格式为:$1 $2 3... 3... 3...n
2.使用双括号括起来
“$*“获取的所有参数拼接为一个字符串,格式为:”$1 $2 3... 3... 3...n”
“$@“获取一组参数列表对象,格式为:”$1” “$2” “ 3 " . . . " 3"... " 3"..."n”
循环语法
for var in 列表变量
do
循环体
done
4.$?变量
用于获取上一个shell命令的退出状态码或者是函数的返回值
每个shell命令的执行都有一个返回值,这个返回值用于说明命令执行是否成功
一般来说,返回0代表命令执行成功,非0代表执行失败
5.$$变量
用于获取当前shell环境的进程ID号
总结:
特殊变量 | 含义 |
---|---|
$n | 获取输入参数$0 :获取当前shell脚本文件名称$1~$9 :获取第一个输入参数到第九个输入参数${10} :获取10和10以上的参数需要使用花括号 |
$# | 获取所有输入参数的个数 |
$* 与$@ | 获取所有输入参数数据 区别:如果不适用双引号,功能一样,获取所有参数数据为一个字符串, 如果使用双引号, $@ 获取的就是参数列表对象,每个参数都是一个独立的字符串 |
$? | 获取上一个命令的退出状态码,一般0代表命令成功,非0代表执行失败 |
$$ | 获取当前shell环境进程的ID号 |
三、shell环境变量深入
3.1自定义系统环境变量
当前用户进入shell环境初始化的时候会加载全局配置文件/etc/profile里面的环境变量,供给所有shell程序使用。
以后只要是所有shell程序或者命令使用的变量,可以定义在这个文件夹中
如何自定义系统级环境变量:
1.系统级全局配置文件:/etc/profile
2.设置环境变量:
export var_name=value
,注意:环境变量建议变量名全部大写3.修改了/etc/profile文件后,要立刻加载修改的数据需要重载配置文件:
source /etc/profile
3.2shell工作环境介绍
用户进入Linux系统就会初始化shell环境,这个环境会加载全局配置文件和用户个人配置文件中环境变量,每个脚本文件都有自己的shell环境
3.2.1shell工作环境分类
交互式与非交互式shell
交互式shell
与用户进行交互,互动效果就是 用户输入一个命令,shell环境立刻反馈相应。
非交互式shell
不需要用户参与就可以执行多个命令。比如一个脚本文件含有多个命令,直接执行并给出结果。
登录shell与非登录shell环境
类型名称 | 含义 |
---|---|
shell登录环境 | 需要用户名\密码登录的shell环境 |
shell非登录环境 | 不需要用户名\密码进入的shell环境 或 执行脚本文件 |
注意:不同的工作环境加载环境变量流程不一样
环境变量初始化流程
1.全局配置文件
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc
2.个人配置文件
当前用户/.bash_profile
当前用户/.bashrc
环境变量加载初始化过程
3.2.2识别shell环境类型
使用$0识别环境
echo $0
输出
-bash
代表:shell登录环境输出
bash
代表:shell非登录环境注意:$0环境变量如果用在子shell中(shell脚本文件)输出shell脚本本身的文件名
3.2.3切换shell环境命令
1.直接登录加载shell登录环境
2.su切换用户加载shell登录与非shell登录环境
su 用户名 --login
或者
su 用户名 -l
# 切换到指定用户,加载shell登录环境变量
su 用户名
# 切换到指定用户,加载shell非登录环境变量
3.bash加载shell登录与非shell登录环境
bash # 加载shell非登录环境
bash -l shell脚本文件 / bash --login shell脚本文件
sh -l shell脚本文件 / sh --login shell脚本文件
# 先加载shell登录环境 然后运行指定shell脚本文件
四、字符串变量
4.1字符串变量格式
字符串(string)就是一系列字符的组合。字符串是shell中最常用的数据类型之一(除了数字和字符串,也没有其他类型了)
字符串的3种格式
- 单引号方式
- 双引号方式(推荐)
- 不用引号方式
var1='abc'
var2="abc"
var3=abc
3种格式区别
1.使用单引号''
的字符串:
任何字符都会原样输出,在拼接字符串中使用变量是无效的。
var1=abc
echo 'abc${var1}'
# 结果
abc${var1}
2.使用双引号""
的字符串:
其中包含了变量,那么该变量会被解析得到值,而不是原样输出。
字符串中还可以出现双引号的子字符串,但需要转义。
var1=zxl
echo "my name is \"${var1}\""
# 结果
my name is "zxl"
3.不用引号的字符串:
不被引号包围的字符串中出现变量时也会被解析,和双引号包围的字符串一样。
字符串中不能出现空格,负责空格后边的字符串会作为其他命令解析。
获取字符串的长度
${#字符串变量名}
在字符串变量名前面加#
获取字符串长度。
4.2字符串拼接方式
# 1.无符号拼接
var1=abc
var2=zxl
echo ${var1}${var2}
# 2.双引号拼接
echo "${var1}${var2}"
# 3.混合拼接
echo ${var1}"$"${var2}
4.3字符串截取
格式 | 说明 |
---|---|
${变量名:start:length} | 从string字符串的左边第start个字符开始 向右截取length个字符。start从0开始 |
${变量名:start} | 从string字符串的左边第start个字符开始截取,直到最后 |
${变量名:0-start:length} | 从string字符串的右边第start个字符开始 向右截取length个字符。start从1开始,右侧第一个字符 |
${变量名:0-start} | 从string字符串左边第一次出现chars的位置开始 截取chars右边的所有字符 |
${变量名#*chars} | 从string字符串左边最后一次出现chars的位置开始 截取chars右边的所有字符 |
${变量名##*chars} | 从string字符串左边开始最后一次出现chars的位置开始 截取chars右边所有的字符 |
${变量名%chars*} | 从string字符串右边第一次出现chars的位置开始 截取chars*左边所有的字符 |
${变量名%%chars*} | 从string字符串右边最后一次出现chars的位置开始 截取chars*左边的所有字符 |
五、索引数组变量
shell支持数组(Array),数组是若干数据的集合,其中的每一份数据都成为数组的元素。
5.1数组的定义
在shell中,用括号( )
来表示数组,数组元素之间用空格分隔
# 方法1:
array_name=(item1 item2 ...)
# 方法2:
array_name=([索引下标1]=item1 [索引下标2]=item2 ...)
# 例如:
nums1=(23 13 66 86 1 5)
nums2=(31 12 2 5 "hello")
nums3=([0]=1 [1]=5 [3]="Linux")
注意:赋值号
=
两边不能有空格
5.2数组的获取
-
通过下标获取元素值,index从0开始
${Arr[index]}
-
获取值同时赋值给其他变量
item=${arr[index]}
-
使用
*
或者@
可以获取数组中的所有元素${arr[@]} ${arr[*]}
-
获取数组的长度或个数
${#arr[*]} ${#arr[@]}
-
获取数组指定元素的字符长度
${#arr[索引]}
5.3数组的拼接
使用@
和*
获取数组所有元素之后进行拼接
array_name=(${array1[@]} ${array2[@]} ...)
array_name=(${array1[*]} ${array2[*]} ...)
5.4数组的删除
删除数组指定元素数据
unset array_name[index]
删除整个数组
unset array_name
六、shell内置命令
shell内置命令,是由Bash Shell自身提供的命令,而不是文件系统中的可执行文件。
使用type来确定一个命令是否是内置命令:
type cd
# 结果
cd 是 shell 内嵌
type ifconfig
# 结果
ifconfig 是 /usr/sbin/ifconfig
通常来说,内置命令会比外部命令执行的更快,执行外部命令时不但会出发磁盘I/O,还需要fork出一个单独的进程来执行,执行完后再退出。而执行内置命令相当于调用当前shell进程的一个函数,还是再当前shell环境进程内,减少上下文切换。
6.1alias创建别名命令
alias用于给命令创建别名。
好处:可以将经常操作比较复杂的命令进行设置别名,通过别名的操作提高工作效率。
若该命令不带任何参数,则显示当前shell进程中的所有别名列表。
# 显示所有别名列表
alias
# alisa别名定义
alias 别名="命令"
# 删除别名
unalias 别名
# 删除当前shell环境中的所有别名
unalias -a
注意:以上两种删除方式都是临时删除当前shell的别名,如果想永久删除必须去配置文件手动删除。
6.2echo输出命令
echo是一个shell内置命令,用与在终端输出字符串,并在最后默认加上换行符。
默认输出换行符
echo 字符串
输出不换行
echo -n 字符串
输出转义字符
\n
转义字符
用于echo输出字符串非结尾处的换行,默认echo无法解析\n
转义字符
echo "hello \nworld"
hello \nworld
-e
参数
用于解析转义符
echo -e '字符串中含有转义字符'
echo -e "hello \nworld"
hello
world
6.3read读取控制台输入命令
read是shell内置命令,用于从标准输入中读取数据并赋值给变量。如果没有进行重定向,默认就是从终端控制台读取用户输入的数据;如果进行了重定向,那么可以从文件中读取数据。
read [-options] [var1 var2 ...]
options
表示选项,var
表示用于存储数据的变量,可以有一个,也可以有多个。
options
和var
都是可选的,如果没有提供变量名,那么读取的数据将存放在环境变量REPLY
变量中。$REPLY保存read最后一个读入命令的数据。
# 举例:
read
123
echo $REPLY
123
# 举例:
read name
zxl
echo $name
zxl
options支持的参数
选项 | 说明 |
---|---|
-a array | 把读取的数据赋值给数组array,从下标0开始。 |
-d delimiter | 用字符串delimiter指定读取结束的位置,而不是一个换行符(读取到的数据不包括delimiter)。 |
-e | 在获取用户输入的时候,对功能键进行编码转换,不会直接显示功能键对应的字符 |
-n num | 读取num个字符,而不是整行字符。 |
-p prompt | 显示提示信息,提示内容为prompt。 |
-r | 原样读取(Raw mode),不把反斜杠字符解释为转义字符。 |
-s | 静默模式(silent mode),不会在屏幕上显示输入的字符。当输入密码和其他确认信息的时候,这是很有必要的 |
-t seconds | 设置超时时间,单位为秒。如果用户没有在指定时间内输入完成,那么read将会返回一个非0的退出状态,表示读取失败。 |
-u fd | 使用文件描述符fd作为输入源,而不是标准输入,类似于重定向。 |
读取多个字符
read -p "请输入姓名,年龄,爱好" name age hobby
echo "姓名:${name}"
echo "年龄:${age}"
echo "爱好:${hobby}"
读取一个字符
read -p "你确定删除数据吗?(请输入y/n)" -n 1 char
printf "\n"
或
read -n 1 -p "你确定删除数据吗?(请输入y/n)" char
echo
# printf "\n" 功能和echo类似,起到换行作用
限制时间输入
在终端控制台输入时,设置指定时间内输入密码
read -t 20 -sp "请输入密码(20秒内)" pwd1
echo
read -t 20 -sp "请再次输入密码(20秒内)" pwd2
printf "\n"
if [ $pwd1 == $pwd2 ]
then
echo "密码一致,验证通过!"
else
echo "密码不一致,验证失败!"
fi
6.4exit退出命令
exit
用于退出当前shell环境进程结束运行,并且可以返回一个状态码,使用$?
可以获取退出状态码。
正确退出
exit
错误退出
exit 非0数字
# 数字建议的范围为0~255,代表命令执行失败。
当shell进程执行出错退出时,可以返回不同的状态值代表不同的错误。
echo "hello"
exit 2
echo "world"
# 执行结果
sh exit.sh
hello # 结果只显示hello,不显示world
echo $? # $?查询状态码是:2
2
6.5declare声明变量
declare命令用于声明shell变量。可用来声明变量并设置变量的属性,也可用来显示shell函数。
declare设置变量的属性
declare [+/-][aArxif][变量名称=设置值]
+/- "-“可以用来指定变量的属性,”+"则是取消变量所设的属性。
a array,设置为普通索引数组
A Array,设置为key-value关联数组
r readonly,将变量设置为只读,也可以使用readonly
x exprot,设置变量为全局变量,也可以使用exprot
i int,设置为整数型变量。
f function,设置为一个函数变量
# 增加为整数变量
declare -i age=20
age=abc #只能赋值为整数
echo $age
0
age=20
echo $age
20
#取消整数型变量
declare +i age
age="abc"
echo $age
abc
#增加只读
declare -r age
age=123
-bash:age:只读变量
实现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
示例:
# 创建索引数组
declare -a array1=(100 bac "hello")
echo "获取array1数组第3个元素:" ${array1[2]}
echo "获取array1数组所有元素:" ${array1[*]} # 或
echo "获取array1数组所有元素:" ${array1[@]}
# 创建关联数组
declare -A array2=(["list1"]=100 ["list2"]=abc ["list3"]="hello")
echo "获取array2数组key="list3"元素:${array2["list3"]}"
echo "获取array2数组所有元素: ${array2[*]}" # 或
echo "获取array2数组所有元素: ${array2[@]}"
七、运算符
7.1算数运算符
expr命令
expr是求值表达式。shell expr是一个功能强大,比较复杂的命令,除了可以实现整数计算,还可以结合一些选项对字符串进行处理。例如:计算字符串长度、字符串比较、字符串匹配、字符串提取等。
expr 算术运算符表达式
# 示例1:
expr 1 + 1
2
result=`expr 算数运算符表达式`
# 示例2:
result=`expr 1 + 1`
echo $result
2
注意:运算符表达式中每个数字与符号之间要用空格。
算数运算符
下表列出了常用的算术运算符,变量a=1,变量b=2
运算符 | 说明 | 举例 |
---|---|---|
+ | 加发 | expr $a +$b 结果为3 |
- | 减法 | expr $a - $b 结果为-1 |
* | 乘法 | expr $a \* $b 结果为2 |
/ | 除法 | expr $b / $a 结果为2 |
% | 取余 | expr $b % $a 结果为0 |
= | 复制 | a=$b 将变量b的值赋值给a |
7.2比较运算符
整数比较运算符
下表中变量a=1,变量b=2
运算符 | 说明 | 举例 |
---|---|---|
-eq | equals检测两个数是否相等,相等返回0,否则返回1 | [$a -eq $b] 返回1 |
-ne | not equals检测两个数是否不相等,不相等返回true | [$a -ne $b]返回0 |
-gt | greater than检测左边的数是否大于右边的,是返回0,否返回1 | [$a -gt $b] 返回1 |
-lt | lower than检测左边的数是否小于右边的,是返回0,否返回1 | [$a -lt $b]返回0 |
-ge | greater equals检测左边的数是否大于等于右边的,是返回0,否返回1 | [$a -ge $b]返回1 |
-le | lower equals检测左边的数是否小于等于右边的,是返回0,否返回1 | [$a -le $b] 返回0 |
< | 检测左边的数是否小于右边的,是返回0,否返回1 | (($a<$b)) 返回0 |
<= | 检测左边数是否小于等于右边的,是返回0,否返回1 | (($a<=$b))返回0 |
> | 检测左边的数是否大于右边的,是返回0,否返回1 | (($a>$b)) 返回1 |
>= | 检测左边的数是否大于等于右边的,是返回0,否返回1 | (($a>=$b)) 返回1 |
== | 检测左边的数是否等于右边的,是返回0,否返回1 | (($a==$b)) 返回1 |
!= | 检测左边的数是否不等于右边的,是返回0,否返回1 | (($a!=$b)) 返回0 |
注意:整数比较运算符只支持整数,不支持小数于字符串,除非字符串的值是整数数字。
每个命令都有返回值,返回0代表成功,返回1代表失败。
字符串比较运算符
下表中变量a为"abc",变量b为"efg"
字符串比较可以使用[[]]
和[]
2种方式
运算符 | 说明 | 举例 |
---|---|---|
==或= | 用于比较两个字符串或数字是否相等,相等返回0 | [$a == $b] 返回1[$a = $b] 返回1[[$a == $b]] 返回1[[$a = $b]] 返回1 |
!= | 用于比较两个字符串或数字是否不相等,不相等返回0 | [$a != $b] 返回0[[$a != $b]]返回0 |
< | 小于返回0,否则返回1 | [$a \< $b] 返回0[[$a < $b]] 返回0 |
> | 大于返回0,否则返回1 | [$a \> $b] 返回1[[$a > $b]] 返回1 |
-z | 检测字符串长度是否为0,是返回0,否则返回1 | [-z $a] 返回1 |
-n | 检测字符串长度是否不为0,是返回0,否则返回1 | [-n $a] 返回0 |
$ | 检测字符串是否不为空,是返回0,否则返回1 | [$] 返回0 |
字符串比较没有
>=
可以通过[["a" > "b" && "a" == "b"]]
来实现。
[[]]
和[]
的区别:
区别1:
[[]]
不会将含有空格字符串进行拆分后比较。
[]
会将还有空格字符串进行查分后比较。
a="a"
b="a b c" # b变量含有空格字符串
# [[]]示例:
[[ $a = $b ]] # 使用[[]]比较正常
echo $?
1 # 结果
# []示例:
[ $a = $b ] # 使用[]比较失败。原因是b变量进行了拆分比较导致失败。
-bash:[:参数太多 # 结果
区别2:
[[]]
对>,<
大于,小于符号不需要转义,
[]
对>,<
大于,小于符号需要转义。
[[ "a" > "b" ]]
[[ "a" < "b" ]]
[ "a" \> "b"]
[ "a" \< "b" ]
7.3布尔运算符
运算符 | 说明 | 举例 |
---|---|---|
! | 非运算,取反 | [ ! 表达式 ] |
-o | or或运算,有一个表达式为true,则返回true | [ 表达式1 -o 表达式2 ] |
-a | and与运算,两个表达式都为true,才返回true | [ 表达式1 -a 表达式2 ] |
注意:布尔运算符放在
[]
或与test命令配合使用才有效
7.4逻辑运算符
运算符 | 说明 | 举例 |
---|---|---|
&& | 逻辑的AND | [[ 表达式1 && 表达式2 ]] |
|| | 逻辑的OR | [[ 表达式1 || 表达式2 ]] |
! | 逻辑非 | [[ ! 表达式 ]] |
注意:
使用
&&
和||
的运算符必须放在[[]]
或者(())
中才有效,否则报错
!
可以用在[]
,[[]]
中使用,不可以在(())
中使用
7.5文件测试运算符
Linux系统文件类型
-:普通文件
d:目录文件
l:链接文件
b:块设备文件
c:字符设备文件
p:管道文件
文件测试运算符
用于检测文件的各种属性
操作符 | 说明 | 举例 |
---|---|---|
-b | 检测文件是否是块设备文件,如果是,返回true | [ -b $file ] |
-c | 检测文件是否是字符设备文件,如果是,返回true | [ -c $file ] |
-d | 检测文件是否是目录,如果是,返回true | [ -d $file ] |
-f | 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,返回true | [ -f $file ] |
-g | 检测文件是否设置了SGID位,如果是,返回true | [ -g $file ] |
-k | 检测文件是否设置了粘着位(Sticky Bit),如果是,返回true | [ -k $file ] |
-p | 检测文件是否是有名管道文件,如果是,返回true | [ -p $file ] |
-u | 检测文件是否设置了SUID位,如果是,返回true | [ -u $file ] |
-r | 检测文件是否可读,如果是,返回true | [ -r $file ] |
-w | 检测文件是否可写,如果是,返回true | [ -w $file ] |
-x | 检测文件是否可执行,如果是,返回true | [ -x $file ] |
-s | 检测文件是否为空(文件大小是否大于0),如果是,返回true | [ -s $file ] |
-e | 检测文件是否存在,如果是,返回true | [ -e $file ] |
file1 -nt file2 | 检测文件1是否比文件2新 | [ file1 -nt file2 ] |
file1 -ot file2 | 检测文件1是否比文件2旧 | [ file1 -ot file2 ] |
可用[]
也可用[[]]
[ -r 文件 ]
# 或
[[ -r 文件 ]]
八、shell计算命令
8.1expr命令
8.1.1求值表达式
expr 算术运算符表达式
# 例如:expr 1 + 1 返回:2
# 例如:expr \( 1 + 1 \) \* 2 + 100 返回:104
获取计算结果赋值给新变量
result=`expr 算术运算符表达式`
# 例如: result=`expr 1 + 1` 输出result得到结果:2
8.1.2字符串语法
-
计算字符串的长度(length)
expr length 字符串 # 例如:expr length "helloworld" 返回10
-
截取字符串(substr)
expr substr 字符串 start end # start 截取字符串的起始位置,从1开始 # end 截取字符串的结束位置,包含这个位置截取 # 例如 expr substr "helloworld" 1 2 返回:he
-
获取第一个字符在字符串中出现的位置(index)
expr index 被查找字符串 需要查找的字符 # 例如: expr index "helloworld" w 返回:6
-
正则表达式(match)
方法1:
expr match 字符串 正则表达式 # 正则表达式默认带有^,代表以什么开头 # 返回值为符合匹配字符的长度,否则返回为0 # 例如:expr match "helloworld" ".*d" 返回:10 # 正则表达式通配符"."代表任意一个字符 # 正则表达式通配符"*"代表签名的字符可以出现0到多次 # ".*d" 含义为匹配字符串中d前面的字符串长度
方法2:
expr 字符串 : 正则表达式 # 正则表达式默认带有^,代表以什么开头 # 返回值为符合匹配字符的长度,否则返回为0 # 例如:expr "helloworld" : ".*d" 返回:10
8.2(())命令
双小括号(( )),用于进行数字运算表达式的执行,将数学运算表达式放在(( ))之间。
可以使用$
获取(( ))表达式命令的结果,这和使用$
获取变量值一样。
((表达式))
用法:
运算操作符/运算命令 | 说明 |
---|---|
((a=1+6)) ((b=a-1)) ((c=a+b)) | 这种写法可以在计算完成后给变量赋值。以((b=a-1))为例,将a-1的运算结果赋值给变量c。使用变量时不用加$前缀,(( ))会自动解析变量名。 |
a=$((1+6)) b=$((a-1)) c=$((a+b)) | 可以在(())前面加上 符号获取 ( ( ) ) 命令的执行结果,获取整个表达式的值。以 c = 符号获取(())命令的执行结果,获取整个表达式的值。以c= 符号获取(())命令的执行结果,获取整个表达式的值。以c=((a+b))为例,将a+b这个表达式的运算结果赋值给变量c。如果c=((a+b))这样写法是错误的,不加$就不能获得表达式的结果。 |
((a>7 && b==c)) | (())也可以进行逻辑运算,在if语句中常会使用逻辑运算。 |
echo $((a+10)) | 需要立即输出表达式的运算结果时,可以再(())前面加$符号。 |
((a=3+5,b=a+10)) | 对多个表达式同时进行计算,多表达式使用, 号隔开。 |
8.3let命令
let命令和双小括号(( ))在数字计算方面功能一样,但是没有(( ))功能强大,let只能用于赋值计算,不能直接输出。不可以条件判断
let 赋值表达式
注意:
1.语法功能等同于
((表达式))
2.多个表达式之间使用空格,不是
,
号。let 变量名1=整数运算表达式1 变量名2=整数运算表达式2 ...
3.对于类似
let a+b
这样的写法,shell虽然计算了a+b的值,但将结果丢弃,如果echo let a+b
会直接输出字符串a+b
;若不想这样,可以使用let sum=a+b
将a+b的结果保存在变量sum中。
8.4$[]命令
和(( )),let命令类似,$[]也只能进行整数运算。但是只能对单个表达式的计算求值和输出。
$[表达式]
# 示例:
a=$[1+6]
echo $a
7 # 结果
1.$[]会对表达式进行计算,并取得计算结果
2.表达式内部不可以赋值给变量
8.5整数运算命令小结
expr
优点:可以直接输出
缺点:计算表达式里面引用变量使用$,特殊字符需要转义,只能计算一个表达式
(())(直接求值输出推荐方式)
优点:直接输出,里面直接使用变量名,特殊字符不需要转义,多个表达式赋值。
缺点:需要获取值以后才可以输出
let(赋值推荐方式)
优点:赋值简单,特殊字符不需要转义。
缺点:不能直接输出
$[]
优点:特殊字符不需要转义
缺点:不能多表达式计算
8.6bc命令
Bash shell内置了对整数运算的支持,但是并不支持浮点运算,而Linux bc(basic calculator)命令可以很方便的进行浮点运算,bc命令是Linux简单的计算器,能进行进制转换与计算。
8.6.1互动式的数学运算
bc [options] [参数]
options
选项 | 说明 |
---|---|
-h | help,帮助信息 |
-v | version,显示命令版本信息 |
-l | mathlib,使用标准数学库,例如使用内置函数就需要使用这个参数 |
-i | interactive,强制交互 |
-w | warn,显示POSIX的警告信息 |
-s | standard,使用POSIX标准来处理 |
-q | quiet,不显示欢迎信息 |
默认使用bc命令后回车会有很多欢迎信息,可以使用
bc -q
回车后不会有欢迎信息可以使用
quit
命令退出bc
内置变量
变量名 | 作用 |
---|---|
scale | 指定精度,对计算结果指定保留小数,默认为0,即不保留小数部分 |
ibase | 指定输入的数字的进制,默认为十进制 |
obase | 指定输出的数字的进制,默认为十进制 |
last或者. | 获取最近计算打印结果的数字 |
内置数学函数
函数名 | 作用 |
---|---|
s(x) | 计算x的正弦值,x是弧度值 |
c(x) | 计算x的余弦值,x是弧度值 |
a(x) | 计算x的反正切值,返回弧度值 |
l(x) | 计算x的自然对数 |
e(x) | 求e的x次方 |
j(n,x) | 贝塞尔函数,计算从n到x的阶数 |
8.6.2shell中非互动式的管道运算
在shell脚本中,可以借助管道符使用bc计算器
直接进行bc的表达式计算输出
echo "expression" | bc [options]
# 实例:
echo "1+1" | bc
2 # 结果
echo "scale=2;10/3" | bc
3.33 # 结果
echo "e(2)" | bc -l
7.38905609893065022723 # 结果
"expression"表达式必须符合bc命令要求的公式
"expression"表达式里面可以引用shell变量
将bc计算结果赋值给shell变量
# 方式1
var_name=`echo "expression" | bc [options]`
# 实例:
b=`echo "1+1" | bc`
echo $b
2 # 结果
# 方式2
var_name=$(echo "expression" | bc [options])
# 实例:
b=$(echo "1+2" | bc)
echo #b
3 # 结果
$()与``功能一样,都是执行里面的命令
区别:``是所有Linux系统支持的方式,兼容性较好,但是容易与引号产生混淆
$()不是所有Linux系统都支持的方式,兼容性较差,但是不容易产线混淆
8.6.3shell中非互动式的输入重定向运算
将计算表达式输出给bc去执行,特点类似于文件中输入,可以输入多行表达式。
# 方式1
var_name=`bc [options] << EOF
第一行表达式1
第二行表达式2
...
EOF
`
# 方式2
var_name=$(bc [options] << EOF
第一行表达式1
第二行表达式2
...
EOF
)
var_name
是shell变量的名字
bc
执行bc命令
EOF...EOF
输入流的多行表达式含义:将EOF中间多行表达式输入给到bc去执行,将bc执行的结果给到shell变量var_name
# 实例
b=`b=bc -l << EOF
1+1
2+2
EOF
`
echo $b
2 4 # 结果 字符串
# 实例
b=$(b=bc -l << EOF
scale=2;10/3
EOF
)
echo $b
3.33 # 结果
九、流程控制
9.1if else语句
if条件判断逻辑控制语句
if语法
if 条件
then
命令
fi
单行写法
if 条件;then 命令;fi
if else语法
if 条件
then
命令
else
命令
fi
if elif else语法
if 条件1
then
命令1
elif 条件2
then
命令2
elif 条件3
then
命令3
...
else
命令n
fi
实例:
read -p "请输入你的考试成绩:" score
if ((score<60 && score>=0))
then
echo "不及格!"
elif ((score>=60 && score<70))
then
echo "及格"
elif ((score>=70 && score<80))
then
echo "中等"
elif ((score>80 && score<90))
then
echo "良好"
elif ((score>90 && score<=100))
then
echo "优秀"
else
echo "成绩不合规"
fi
9.1.1if 条件判断的退出状态
Linux任何命令的执行都会有一个退出状态,无论是内置命令,外部文件命令,还是自定义的shell函数,当他退出(运行结束)时,都会返回一个比较小的整数值给调用(使用)它的程序,这就是命令的退出状态。
大多数命令状态0代表成功,非0代表失败,也有特殊的命令,比如diff命令用来比较两个文件的不同,对于“没有差别”的文件返回0,对于“找到差别”的文件返回1,对于无效文件名返回2。
shell if语句使用逻辑运算符将多个退出状态组合起来,这样就可以一次判断多个条件
运算符 | 使用格式 | 说明 |
---|---|---|
&& 或 -a | 条件1&&条件2 | 逻辑与运算符,当条件1和条件2同时成立时,整个表达式才成立。如果检测到条件1不成立,就不会再检测条件2了, |
|| 或 -o | 条件1||条件2 | 逻辑或运算符,条件1和条件2两个表达式中只要有一个成立,整个表达式就成立。 |
! | !条件 | 逻辑非运算符,相当于"取反"的效果。 |
9.2test命令
shell中test命令用于检查某个条件是否成立。可以进行数值、字符和文件三方面测试。
功能和[ ]一样
整数比较测试
if test 数字1 options 数字2
then
...
fi
options具体如下:
参数 | 说明 |
---|---|
-eq | 等于则为真 |
-ne | 不等于则为真 |
-gt | 大于则为真 |
-lt | 小于则为真 |
-ge | 大于等于则为真 |
-le | 小于等于则为真 |
示例:
test 1 -eq 1;echo $?
0 # 结果
test 1 -lt 2;echo $?
0 # 结果
字符串比较测试
参数 | 说明 |
---|---|
= 或 == | 等于,等于返回0,代表成功。否则返回1代表失败 |
!= | 不等于 |
\< | 小于 |
\> | 大于 |
-z 字符串 | 字符串的长度为零则为真 |
-n 字符串 | 字符串的长度不为零则为真 |
示例:
test "a" == "b";echo $?
1 # 结果
test "a" \> "b";echo $?
1 # 结果 >和<符号需要转义\
文件比较测试
参数 | 说明 |
---|---|
-e 文件名 | exists,如果文件存在则为真 |
-r 文件名 | read,如果文件存在且可读则为真 |
-w 文件名 | write,如果文件存在且可写则为真 |
-x 文件名 | execute,如果文件存在且可执行则为真 |
-s 文件名 | string,如果文件存在且至少有一个字符则为真 |
-d 文件名 | directory,如果文件存在且为目录则为真 |
-f 文件名 | file,如果文件存在且为普通文件则为真 |
-c 文件名 | character,如果文件存在且字符型特殊文件则为真 |
-d 文件名 | 如果文件存在且为块特殊文件则为真 |
示例:
test -e new.txt;echo $?
0 # 结果
小结
-
test命令对整数比较测试
test 整数1 options 整数2
options:
lt le gt ge eq ne
-
test命令对字符串比较测试
test 变量1 options 变量2
options:
> < != ==
> <
需要转义 -
test命令对文件比较测试
test options 文件路径字符串
options:
-w -r -e -x -s -d
9.3case语句
shell case语句为多选择语句。可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。
当分支较多,且判断条件比较简单时,使用 case in 语句。
语法:
case 值 in
匹配模式1)
命令1
命令2
...
;;
匹配模式2)
命令1
命令2
...
;;
esac
每一匹配模式必须以有括号结束。取值可以为变量或常数。匹配发现取值符号某一模式后,其间所有命令开始执行,直至;;
(类似break,不可以替代否则语法错误)。取值将检测匹配的每一个模式。一旦模式匹配,则执行完成匹配模式相应命令后不再继续其他模式,使用星号*捕获该值,在执行后面的命令。
case,in和esac都是shell关键字,esac就是case的反写,代表结束case
匹配模式:可以是一个数字、一个字符、或者一个简单的正则表达式。
简单正则表达式支持以下通配符
格式 | 说明 |
---|---|
* | 表示任意字符串 |
[abc] | 表示a、b、c三个字符中的任意一个。 |
[m-n] | 表示从m到n的任意一个字符。比如:[0-9]表示任意一个数字 |
| | 表示多重选择,类似逻辑运算中的或运算。比如:abc | xyz表示匹配字符串"abc" 或者"xyz" |
示例:
#!/bin/bash
read -p "请输入一个0-7的数字:" number
case $number in
1)
echo "星期一"
;;
2)
echo "星期二"
;;
3)
echo "星期三"
;;
4)
echo "星期四"
;;
5)
echo "星期五"
;;
6)
echo "星期六"
;;
7)
echo "星期天"
;;
*)
echo "输入的数字无效"
;;
esac
9.4while语句
while用于循环执行一些列命令
多行写法:
while 条件
do
命令1
命令2
...
continue; # 结束当前这一次循环,进入下一次循环
break; # 结束当前循环
done
单行写法:
while 条件; do 命令; done;
示例:
#!/bin/bash
read -p "请输入一个循环数字:" number
i=0
while ((i<number))
do
echo "hello${i}"
let i++;
done
无限循环
while :
do
command
done
或
while ture
do
command
done
9.5until语句
until也是循环结构语句,until循环与while循环在处理方式上刚好相反,循环条件为false会一直循环,条件为true停止循环。
语法:
until 条件
do
命令
done
条件如果返回值为1(代表false),则继续执行循环体内的语句,否则跳出循环。
示例:
#!/bin/bash
read -p "请输入一个循环数字:" number
i=0
until [[ ! $i < $number ]]
do
let i++
echo "hello${i}"
done
9.6for语句
shell支持for循环,与其他编程语言类似
9.6.1循环方式1
语法:
# 多行写法
for var in item1 item2 ... itemN
do
命令1
命令2
...
done
# 单行写法
for var in item1 item2 ...itemN; do 命令1;命令2; done;
示例:
#!/bin/bash
read -p "请输入一个循环的数字:" number
i=0
for i in 1 3 5 6
do
echo "hello${i}"
done
9.6.2循环方式2
语法:
# 多行写法
for var in {start..end}
do
命令
done
# 单行写法
for var in {start..end}; do 命令; done
start:循环范围的起始值,必须为整数
end:循环范围的结束值,必须为整数
示例:
#!/bin/bash
for i in {1..10}
do
echo "hello${i}"
done
9.6.3循环方式3
语法:
# 多行写法
for((i=start;i<=end;i++))
do
命令
done
# 单行写法
for((i=start;i<=end;i++)); do 命令; done
示例:
for((i=1;i<=5;i++)); do echo "hello world ${i}"; done
无线循环
for((;;)); do 命令; done
9.7select语句
select in 循环用来增强交互性,它可以显示出带编号的菜单,用户输入不同的编号就可以选择不同的菜单,并执行不同的功能。select in是shell独有的一种循环。
语法:
select var in menu1 menu2...
do
命令
done
注意:select是无限循环(死循环),输入空值或者输入的值无效,都不会结束循环,只有遇到break语句,或者按下ctrl+d组合键才能结束循环
执行命令过程中:终端会输出
#?
代表可以输入选择的菜单编号
示例1:
#!/bin/bash
echo "您的爱好是什么?"
select hobby in "编程" "游戏" "篮球" "游泳"
do
echo $hobby
break
done
echo "您的爱好是${hobby}"
示例2:
#!/bin/bash
echo "你的爱好是什么?"
select hobby in "编程" "游戏" "篮球" "游泳"
do
case $hoby in
"编程")
echo "编程多敲代码"
break
;;
"游戏")
echo "少玩游戏"
break
;;
"篮球"|"游泳")
echo "运动有利健康"
break
;;
*)
echo "输入错误,请重新输入"
esac
done
十、shell函数
shell编程和其他编程一样,有函数,函数是由若干条shell命令组成的语句块,实现shell脚本代码重用和模块化编程。
10.1系统函数
系统自带提供的函数,可以直接使用
basename系统函数
basename函数用于获取文件名的函数,根据给出的文件路劲截取文件名
basename [string / pathname] [suffix]
根据指定字符串或路径名进行截取文件名。比如:根据路径“/one/two/aa.txt”,可以截取出aa.txt
suffix:用于截取的时候去掉指定的后缀名
basename ./controll.sh
controll.sh # 结果
basename ./controll.sh .sh
controll # 结果
dirname系统函数
从指定的文件绝对路径,去除文件名,返回剩下的前缀目录路径。
dirname 文件绝对路径
示例:
dirname ./contrill.sh
. # 结果
dirname /root/contrill.sh
/root # 结果
10.2自定义函数
语法:
# 函数的定义
[ function ] funname()
{
命令
[return 返回值]
}
# 调用函数
funname 传递参数1 传递参数2...
可以带function fun()定义,也可以直接fun()定义,不带任何参数。
参数返回,可以显示加:return返回,如果不加,将以最后一条命令运行结果,作为返回值。return后跟数值n(0-255)
必须在调用函数地方之前,先声明函数,shell脚本是逐行运行,只要先运行了函数,后面才可以使用函数。
无参无返回值函数
#!/bin/bash
demo()
{
echo "执行函数"
}
# 调用函数
demo
无参有返回值函数
#!/bin/bash
sum()
{
echo "求两个数的和!"
read -p "请输入第一个数字:" n1
read -p "请输入第二个数字:" n2
echo "两个数字分别是$n1和$n2"
return $(($n1+$n2))
}
sum
echo "两个数的和为:$?"
有参函数
在shell中,调用函数时可以向其传递参数。在函数体内部,通过$n
的形式来获取参数的值,例如:$1
表示第一个参数,$2
表示第二个参数…
参数处理 | 说明 |
---|---|
$# | 传递到脚本或函数的参数个数 |
$* | 以一个单字符显示所有向脚本传递的参数 |
$$ | 脚本运行的当前进行ID号 |
$! | 后台运行的最后一个进程的ID号 |
$@ | 与$*相同,但是使用时加双引号,并在引号中返回每个参数。 |
$? | 显示最后命令的退出状态。0表示成功,其他表示错误。 |
示例:
#!/bin/bash
funParam()
{
echo "第一个参数为:$1"
echo "第二个参数为:$2"
echo "第十个参数为:${10}"
echo "参数总数有$#个"
echo "获取所有参数作为一个字符串返回:$*"
}
# 调用
funParam 1 2 3 4 5 6 7 8 9 10 22
10.3shell程序与函数的区别
函数和shell程序比较相似,区别在于:
shell程序(内置命令和外部脚本文件),外部脚本文件是在子shell中运行,会开启独立的进程运行。
shell函数在当前shell的进程中运行,没有开启进程。
#!/bin/bash
demo(){
echo "函数中打印当前进程ID:$$"
}
echo "当前脚本文件(shell程序)打印当前进程ID:$$"
# 调用函数
demo
十一、shell重定向输入输出
标准输入介绍
从键盘读取用户输入的数据,然后再把数据拿到shell程序中使用;
标准输出介绍
shell程序产生的数据,这些数据一般都是呈现到显示器上供用户浏览查看;
默认输入输出文件
每个Unix/Linux命令运行时都会打开三个文件:
文件名 | 类型 | 文件描述符(file description,fd) | 功能 |
---|---|---|---|
stdin | (standard input)标准输入文件 | 0 | 获取键盘的输入数据 |
stdout | (standard output)标准输出文件 | 1 | 将正确数据输出到显示器上 |
stderr | (standard error)标准错误输出文件 | 2 | 将错误信息输出到显示器上 |
每个文件都有一个唯一的文件描述符fd
11.1重定向输入输出介绍
标准输入是数据默认从键盘流向程序,如果改变了它的方向,数据就从其他地方流入,这就是输入重定向。
标准输出是数据默认从程序流向显示器,如果改变了它的方向,数据就流向其他地方,这就是输出重定向。
重定向的作用:
输出重定向是指命令的结果不在输出到显示器上,而是输出到其他地方,一般是文件中。这样做的最大好处是把命令的结果保存起来。
语法:
命令 | 说明 |
---|---|
命令 > file | 将正确数据重定向输出到file文件中,覆盖方式 |
命令 < file | 将输入重定向从file文件中读取数据 |
命令 >> file | 将正确数据重定向输出到file文件中,追加方式 |
命令 < file1 > file2 | 从file文件读取数据,输出数据到file2文件中 |
命令 fd> file | 根据指定的文件描述符fd将数据重定向输出到file文件中,覆盖方式 |
命令 fd>> file | 根据指定的文件描述符fd将数据重定向输出到file文件中,追加方式 |
命令 > file fd1>&fd2 | 将fd1和fd2文件描述符合并,输出到文件 |
fd1 <& fd2 | 将fd1和fd2文件描述符合并,从文件读取输入 |
<< tag | 读取终端输入数据,将开始标记tag和结束标记tag之间的内容作为输入。 |
在输出重定向中,
>
代表的是覆盖输出,>>
代表是追加输出。fd是文件描述符。
0是标准输入(stdin)
1是标准输出(stdout)
2是标准错误输出(stderr)
fd> 或 fd>> 中间不能有空格。
11.2重定向输出
示例:
echo "hello" > log.txt # 覆盖
cat log.txt
hello # 结果
echo "hello2" >> log.txt # 追加
cat log.txt
hello # 结果
hello2 # 结果
ll adasdasddas 2>> log.txt # 输出错误信息
cat log.txt
hello # 结果
hello2 # 结果
ls:无法访问adasdasddas:没有那个文件或目录 # 结果
ll adasdasddas >> log.txt 2>&1 # 输出正确和错误信息
cat log.txt
hello # 结果
hello2 # 结果
ls:无法访问adasdasddas:没有那个文件或目录 # 结果
11.2重定向输入
wc命令
wc [options] [文件名]
options如下:
选项 | 含义 |
---|---|
-c | 统计字节数 |
-w | 统计单词数 |
-l | 统计行数 |
示例:
wc -l < log.txt
3 # 结果
while read str; do echo $str; done < log.txt
hello # 结果
hello2 # 结果
ls:无法访问adasdasddas:没有那个文件或目录 # 结果
wc l << EOF
> a
> b
> c
> d
> EOF
4 # 结果
十二、shell好用的工具
12.1cut工具
cut译为"剪切,切割",是一个强大的文本处理工具,它可以将文本按列进行切分的文本处理。cut命令逐行读入文本,然后按列划分字段进行提取,输出等操作。
cut [options] filename
options参数:
选项参数 | 功能 |
---|---|
-f提取范围 | 列号,获取第几列 |
-d自定义分隔符 | 自定义分隔符,默认为制表符 |
-c提取范围 | 以字符为单位进行分割 |
-b提取范围 | 以字节为单位进行分割。这些字节位置将忽略多字节字符边界,除非也指定了-n标志 |
-n | 与-b选项连用,不分割多字节字符 |
提取范围说明:
提取范围 | 说明 |
---|---|
n- | 提取指定第n列或字符或字节后面所有数据 |
n-m | 提取指定第n列或字符或字节到第m列或字符或字节中间的所有数据 |
-m | 提取指定第m列或字符或字节前面所有数据 |
n1,n2,… | 提取指定枚举的所有数据 |
示例:
cut cut1.txt -d " " -f 1
a # 结果
b # 结果
c # 结果
cut cut1.txt -d " " -f 1-2
aa # 结果
bb # 结果
cc # 结果
echo "abc你好" | cut -nb 1-4
abc你 # 结果 忽略多字节字符边界
# 切割bash进程ip
ps -aux | grep bash | head -n 1 | cut -d " " -f 8
1337 # 结果
# 切割ip
ifconfig | grep broadcast | cut -d " " -f 10
192.168.56.102 # 结果
head命令
head [options] 文件名
options参数:
选项参数 | 功能 |
---|---|
-n | 指定显示文件开头的行数,默认为10行 |
-c | 指定显示文件开始部分的字节数 |
-q | 不打印任何警告信息到标准错误输出 |
-v | 即使文件不存在也要报告相关信息 |
12.2sed工具
sed(stream editor,流编辑器)是Linux下一款强大的非交互式流式文本编辑器(vim是交互式文本编辑器),可以对文本文件的每一行数据匹配查询之后进行增、删、改、查等操作,支持按行、按字段、按正则匹配文本内容,灵活方便,特别适合于大文本的编辑。
sed是一种流编辑器,它一次处理一行内容,将这行放入缓存(模式空间),然后才对这行进行处理,处理完后,将缓存区的内容发送到终端。
sed [选项参数] [模式匹配/sed程序命令] [文件名]
# 模式匹配,sed会读取每一行数据到模式空间中,之后判断当前行是否符合模式匹配要求,符合要求就会执行sed程序命令,否则不会执行sed命令,如果不写匹配模式,那么每一行都会执行sex程序命令
选项参数:
选项参数 | 功能 |
---|---|
-e | 直接在命令模式上进行sed的动作编辑。它告诉sed将下一个参数解释为一个sed指令,只有当命令行上给出多个sed指令时才需要使用-e选项,一行命令语句可以执行多条sed命令 |
-i | 直接对内容进行修改,不加-i时默认只是预览,不会对文件做实际修改 |
-f | 后跟保存了sed指令的文件 |
-n | 取消默认输出,sed默认会输出所有文件内容,使用-n参数后只显示处理过的行 |
-r | 使用扩展正则表达式,默认情况sed只识别基本正则表达式* |
sed程序命令功能描述:
命令 | 功能描述 |
---|---|
a | add新增,a的后面可以接字串,在下一行出现 |
c | change更改,更改匹配行的内容 |
d | delete删除,删除匹配的内容 |
i | insert插入,响匹配前插入内容 |
p | print打印,打印出匹配的内,通常与-n选项合用 |
s | substitute替换,替换掉匹配的内容 |
= | 用于打印被匹配的行的行号 |
n | 读取下一行,遇到n时会自动跳入下一行 |
特殊符号:
命令 | 功能描述 |
---|---|
! | 就像一个sed命令,放在限制条件后面,对指定行以外的所有行应用命令(取反) |
{sed命令1;sed命令2} | 多个命令操作同一个的行 |
向文件中添加数据
# 向第三行后面增加hello
sed '3ahello' sed.txt
# 向指定内容前后增加hello
sed '/abc/ihello' sed.txt # 在指定的abc前面添加hello
sed '/abc/ahello' sed.txt # 在指定的abc后面添加hello
# 在最后一行后面添加hello
sed '$ahello' sed.txt
3,代表第三行
a,代表在后面添加,出现在下一行
i,代表在前面添加,出现在上一行
$,代表在最后一行添加
注意:没有修改源文件
文件中删除数据
# 删除第二行
sed '2d' sed.txt
# 删除奇数行
sed '1~2d' sed.txt # 1~2表示从第一行开始,间隔2行
# 删除指定范围的多行数据
sed '1,3d' sed.txt # 删除第1行到第3行的数据
# 删除第一行到第三行的取反数据
sed '1,3!d' sed.txt
# 删除最后一行数据
sed '$d' sed.txt
# 删除匹配abc的行
sed '/abc/d' sed.txt
# 删除匹配abc到最后一行
sed '/abc/$d' sed.txt
d,代表删除
1~2,代表从第1行开始,间隔2行
1,3,代表从第1行到第3行
1,3!,代表从第1行到第3行取反的数据
更改文件中的数据
# 将文件的第一行改为hello
sed '1chello' sed.txt
# 将包含abc的行修改为hello
sed '/abc/chello' sed.txt
# 将最后一行修改为hello
sed '$chello' sed.txt
# 将文本中的abc替换为hello
sed 's/abc/hello/' sed.txt # 默认只替换每行第一个abc
# 将文本中的所有abc替换为hello
sed 's/abc/hello/g' sed.txt
# 将文本中的第二个abc替换为hello
sed 's/abc/hello/2' sed.txt
# 将文本中每行末尾拼接test
sed 's/$/& test/' sed.txt
c,代表修改
s,代表替换
g,代表所有
2,代表第二个
&,代表拼接
查询文件或管道中的数据
# 查询含有abc的行数据
sed -n '/abc/p' sed.txt
# 管道查询所有进程中含有sshd的进程信息命令
ps -aux | grep sshd # 方式1
ps -aux | sed -n '/sshd/p' # 方式2
-n,代表匹配
p,代表打印
多个sed程序命令执行
# 将sed.txt文件中的第一行删除并将abc替换为hello
sed -e '1d' -e 's/abc/hello/g' sed.txt
sed '1d;s/abc/hello/g' sed.txt
12.2.1缓存区数据交换
模式空间与暂存空间
sed把文件读出来每一行存放的空间叫模式空间,会在改空间中对读到的内容做相应处理。
暂存空间刚开始里面只有个空行。
sed可以使用相应的命令从模式空间往暂存空间放入内容或从暂存空间取内容放入模式空间
缓存区sed程序命令:
命令 | 含义 |
---|---|
h | 将模式空间里面的内容复制到暂存空间缓存区(覆盖方式) |
H | 将模式空间里面的内容复制到暂存空间缓存区(追加方式) |
g | 将暂存空间里面的内容复制到模式空间缓存区(覆盖方式) |
G | 将缓存空间里面的内容复制到模式空间缓存区(追加方式) |
x | 交换2个空间的内容 |
示例:
1、第一行粘贴到最后一行(将模式空间第一行复制到暂存空间【覆盖方式】,并将暂存空间的内容复制到模式空间中的最后一行【追加方式】)
sed '1h;$G' sed.txt
2、第一行删除后粘贴到最后一行(将模式空间第一行复制到暂存空间【覆盖方式】并删除,最后将暂存空间的内容复制到模式空间中的最后一行【追加方式】)
sed '1{h;d};$G' sed.txt # 多个命令操作同一行数据使用{}括起来
3、第一行数据复制粘贴替换其他行数据(将模式空间第一行复制到暂存空间【覆盖方式】,最后将暂存空间的内容复制到模式空间中替换从第二行开始到最后一行的每一行数据【覆盖方式】)
sed '1h;2,$g' sed.txt
4、将前三行的数据复制粘贴到最后一行(将前三行数据复制到暂存空间【追加方式】,之后将暂存空间的所有内容复制粘贴到模式空间最后一行)
sed '1,3H;$G' sed.txt
5、给每一行添加空行
sed 'G' sed.txt
6、删除文件中的空行
sed '/^$/d' sed.txt
12.3awk工具
awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大,简单来说awk就是把文件逐行的读入,以空格为默认分割符将每行切片,切开的部分再进行各种分析处理,因为切开的部分使用awk可以定义变量,运算符,使用流程控制语句进行深度加工与分析。
awk [options] 'pattern{action}' {filenames}
options:选项参数
pattern:表示awk在数据中查找的内容,就是匹配模式
action:在找到匹配内容时执行的一些列命令
选项参数:
选项参数 | 功能 |
---|---|
-F | 指定输入文件拆分分隔符 |
-v | 赋值一个用户定义变量 |
awk内置变量
内置变量 | 含义 |
---|---|
ARGC | 命令行参数个数 |
ARGV | 命令行参数排列 |
ENVIRON | 支持队列中系统环境变量的使用 |
FILENAME | awk浏览的文件名 |
FNR | 浏览文件的记录数 |
FS | 设置输入域分隔符,等价与命令行-F选项 |
NF | 浏览记录的域的个数,根据分隔符分割后的列数 |
NR | 已读的记录数,也是行号 |
OFS | 输出域分隔符 |
ORS | 输出记录分隔符 |
RS | 控制记录分隔符 |
$n | $0变量是指定整条记录。$1表示当前行的第一个域,$2表示当前行的第二个域…以此类推 |
$NF | $NF是number finally,表示最后一列的信息,跟变量NF是由区别的,变量NF统计的是每行列的总数 |
示例:
1、默认每行空格切割数据
echo "abc 123 456" | awk '{print $!"&"$2"&"$3}'
abc&123&456 # 结果
print:打印
2、打印含有匹配信息的行(搜索passwd文件有root关键字的所有行)
awk '/root/{print $0}' passwd
3、打印匹配行中第7列数据(搜索passwd文件中有root关键字的所有行,然后以“:”拆分并打印输出第七列)
awk -F: '/root/{print $7}' passwd
awk -f ":" '/root/{print $7}' passwd
4、打印文件每行属性信息(统计passwd文件名,每行的行号,每行的列数,对应的完整行内容)
awk -F: 'print "文件名:"FILENAME",行号:"NR",列数:"NF",内容:"$0' passwd
awk -F: '{printf("文件名:%s,行号:%s,列数:%s,内容:%s\n",FILENAME,NR,NF,$0)}' passwd
printf:将字符串格式化输出
\n:换行
5、打印第二行信息
awk -F: 'NR==2{printf(filename:%s,内容:%s\n,FILENAME,$0)}' passwd
6、查找以c开头的资源
ls -a | awk '/^c/'
7、打印第一列信息
awk -F: '{print $1}' passwd
8、打印最后一列信息
awk -F: '{print $NF}' passwd
9、打印倒数第二列信息
awk -F: '{print $(NF-1)}' passwd
10、打印10到20行的第一列信息
awk -F: '{if(NR>=10 && NR<=20){print $1}}' passwd
11、多分隔符使用
echo "one:two/three" | awk -F "[:/]" '{print $1"&"$2"&"$3}'
12、添加开始与结束内容
echo -e "abc\nabc" | awk 'BEGIN{pinrt "开始..."}{print $0}END{print:"结束..."}'
13、使用循环拼接分割后的字符串
echo "abc asd qwe" | awk '{print $1"&"$2"&"$3}'
echo "abc asd qwe" | awk -v str="" '{for(n=1;n<=NF;n++){str=str$n}} END{print str}'
14、操作指定数字运算
echo "2.1" |awk -v i=1 '{print $0+i}'
15、切割ip
ifconfig | awk '/broadcast/{print $0}' | awk '{print $2}'
16、显示空行行号
sed 'G' sed.txt | awk '/^$/{print NR}'
小结:
grep:用于查找匹配的行
cut:截取数据,截取某个文件中的列,重点是按照列分割,不适合截取文件中有多个空白字符的字段。
sed:增删改查数据,用于在文件中以行来截取数据进行增删改查
awk:截取查询分析数据,可以在某个文件中以竖列来截取分析数据,如果字段之间有很多空白字符也可以获取所需要的数据。