Bootstrap

Shell基础学习笔记

shell脚本

打印当前系统环境使用的shell解析器类型

echo $SHELL

一、shell脚本文件编写规范

1.1脚本文件后缀名规范

shell脚本文件就是一个文本文件,后缀名使用.sh结尾

1.2首行格式规范

#!/bin/bash

含义:设置当前shell脚本文件才用bash解析器运行

1.3shell脚本文件的3种执行方式

  1. sh解析器执行方式

    语法:sh 脚本文件

    介绍:利用sh命令执行脚本文件,本质就是使用shell解析器运行脚本文件

  2. bash解析器执行方式

    语法:bash 脚本文件

    介绍:利用bash命令执行脚本文件,本质就是使用shell解析器运行脚本文件

  3. 仅路径执行方式

    语法:./脚本文件

    介绍:执行当前目录下的脚本文件

    注意:脚本文件自己执行需要具有可执行权限,否则无法执行

    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特殊变量

  1. $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种格式

  1. 单引号方式
  2. 双引号方式(推荐)
  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数组的获取

  1. 通过下标获取元素值,index从0开始

    ${Arr[index]}
    
  2. 获取值同时赋值给其他变量

    item=${arr[index]}
    
  3. 使用*或者@可以获取数组中的所有元素

    ${arr[@]}
    ${arr[*]}
    
  4. 获取数组的长度或个数

    ${#arr[*]}
    ${#arr[@]}
    
  5. 获取数组指定元素的字符长度

    ${#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表示用于存储数据的变量,可以有一个,也可以有多个。

optionsvar都是可选的,如果没有提供变量名,那么读取的数据将存放在环境变量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

运算符说明举例
-eqequals检测两个数是否相等,相等返回0,否则返回1[$a -eq $b]返回1
-nenot equals检测两个数是否不相等,不相等返回true[$a -ne $b]返回0
-gtgreater than检测左边的数是否大于右边的,是返回0,否返回1[$a -gt $b]返回1
-ltlower than检测左边的数是否小于右边的,是返回0,否返回1[$a -lt $b]返回0
-gegreater equals检测左边的数是否大于等于右边的,是返回0,否返回1[$a -ge $b]返回1
-lelower 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布尔运算符

运算符说明举例
!非运算,取反[ ! 表达式 ]
-oor或运算,有一个表达式为true,则返回true[ 表达式1 -o 表达式2 ]
-aand与运算,两个表达式都为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字符串语法
  1. 计算字符串的长度(length)

    expr length 字符串
    # 例如:expr length "helloworld" 返回10
    
  2. 截取字符串(substr)

    expr substr 字符串 start end
    # start 截取字符串的起始位置,从1开始
    # end 截取字符串的结束位置,包含这个位置截取
    # 例如 expr substr "helloworld" 1 2 返回:he
    
  3. 获取第一个字符在字符串中出现的位置(index)

    expr index 被查找字符串 需要查找的字符
    # 例如: expr index "helloworld" w 返回:6
    
  4. 正则表达式(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

选项说明
-hhelp,帮助信息
-vversion,显示命令版本信息
-lmathlib,使用标准数学库,例如使用内置函数就需要使用这个参数
-iinteractive,强制交互
-wwarn,显示POSIX的警告信息
-sstandard,使用POSIX标准来处理
-qquiet,不显示欢迎信息

默认使用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	# 结果

小结

  1. test命令对整数比较测试

    test 整数1 options 整数2

    options:lt le gt ge eq ne

  2. test命令对字符串比较测试

    test 变量1 options 变量2

    options:> < != ==

    > < 需要转义

  3. test命令对文件比较测试

    test options 文件路径字符串

    options:-w -r -e -x -s -d

9.3case语句

shell case语句为多选择语句。可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。

当分支较多,且判断条件比较简单时,使用 case in 语句。

语法:

casein
匹配模式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
donewhile 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程序命令功能描述:

命令功能描述
aadd新增,a的后面可以接字串,在下一行出现
cchange更改,更改匹配行的内容
ddelete删除,删除匹配的内容
iinsert插入,响匹配前插入内容
pprint打印,打印出匹配的内,通常与-n选项合用
ssubstitute替换,替换掉匹配的内容
=用于打印被匹配的行的行号
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支持队列中系统环境变量的使用
FILENAMEawk浏览的文件名
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:截取查询分析数据,可以在某个文件中以竖列来截取分析数据,如果字段之间有很多空白字符也可以获取所需要的数据。

;