以主机A连接主机B为例,主机A为SSH客户端,主机B为SSH服务端。
在服务端即主机B上:
/etc/ssh/sshd_config | ssh服务程序sshd的配置文件 |
/etc/ssh/ssh_host_* | 服务程序sshd启动时生成的服务端公钥和私钥文件。如ssh_host_rsa_key和ssh_host_rsa_key.pub。 《1》其中.pub文件是主机验证时的host key,将写入到客户端的~/.ssh/known_hosts文件中。 《2》其中私钥文件严格要求权限为600,若不是则sshd服务可能会拒绝启动 |
~/.ssh/authorized_keys | 保存的是基于公钥认证机制时来自于客户端的公钥。在基于公钥认证机制认证时,服务端将读取该文件--在客户端即主机A上。 |
/etc/ssh/ssh_config | 客户端的全局配置文件 |
~/.ssh/config | 客户端的用户配置文件,生效优先级高于全局配置文件。一般该文件默认不存在。该文件对权限有严格要求只对所有者有读/写权限,对其他人完全拒绝写权限。 |
~/.ssh/known_hosts | 保存主机验证时服务端主机host key的文件。文件内容来源于服务端的ssh_host_rsa_key.pub文件。 |
/etc/ssh/known_hosts | 全局host key保存文件。作用等同于~/.ssh/known_hosts |
~/.ssh/id_rsa | 客户端生成的私钥。由ssh-keygen生成。该文件严格要求权限,当其他用户对此文件有可读权限时,ssh将直接忽略该文件 |
~/.ssh/id_rsa.pub | 私钥id_rsa的配对公钥。对权限不敏感。当采用公钥认证机制时,该文件内容需要复制到服务端的~/.ssh/authorized_keys文件中 |
~/.ssh/rc | 保存的是命令列表,这些命令在ssh连接到远程主机成功时将第一时间执行,执行完这些命令之后才开始登陆或执行ssh命令行中的命令。 /etc/ssh/rc :作用等同于~/.ssh/rc。 |
ssh还可以实现主机跳转,即跳板功能。例如主机B能和A、C通信,但A、C之间不同通信,即A<-->B<-->C<-x->A的情形。如果要从A登陆到C,则可以借助B这个跳板登录到C。
此处一个简单示例为:从172.16.10.5登录到172.16.10.6,再以此为基础登录到172.16.10.3上。
运行shell脚本的方法有两种:①作为可执行程序运行 ②作为解释器参数运行
注意: 在编写ssh脚本时,凡是[]里面的内容都需要空格隔开,括号与内容也需要空格隔开!!
检查shell脚本:
①语法错误:会导致后续的命令不继续执行,可以用 bash -n 检查错误,提示的出错行数不一定是准确的
②命令错误:默认后续的命令还会继续执行,用 bash -n 无法检查出来 ,可以使用 bash -x 进行观察
③逻辑错误:只能使用 bash -x 进行观察
④此选项只能检测脚本中的语法错误,不能检测命令错误,也不会执行脚本 bash -n test.sh #bash -n 脚本名称
⑤逐行输出命令,并输出执行结果 bash -x test.sh #bash -x 脚本名称
一、shell变量:
变量数据类型: 字符; 数值(整形,浮点型) bash不支持浮点数; 布尔; 指针; 结构体
静态与动态语言:
静态编译语言:在使用变量前,先声明变量类型,只会类型不能改变
动态编译语言:不用事先声明,可随时改变类型
强类型与弱类型语言:
强类型语言:不同类型的数据操作,必须警告强制转换才同一类型才能运行
弱类型语言:语言的运行会隐式做数据类型转换,无需指定类型,默认均为字符型,参与运算会自动进行隐式类型转换,变量无须事先定义,可直接调用。
二、变量命名法则:
要求:①区分大小写 ②不使用程序中的保留字和内置变量 ③只能使用数字,字母及下划线,且不能以数字开头。
shell脚本中存在的变量:
①局部变量:在脚本或命令中定义,仅在当前shell实例中有效,其他shell程序启动时不能访问局部变量。局部变量小写 函数名小写
书写格式:大驼峰【StudentFirstName】 小驼峰【studentFirstName】
②环境变量:所有的程序,包括shell启动的程序,都能访问环境变量,必要时候,shell脚本也可以定义环境变量。 大写
③shell变量:由shell程序设置的特殊变量,shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行。
三、变量赋值与引用
(变量赋值时等号左右两边不能有空格!!!)
name='root' #直接字串
name="$USER" #变量引用
name=`COMMAND` #命令引用
name=$(COMMAND) #命令引用
注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存,脚本中的变量会随着脚本结束,也会自动删除。
#变量保存、变量永久保存方法、变量永久保存路径
在/etc/profile文件中添加变量【对所有用户生效(永久的)】 [root@bogon ~]# vim /etc/profile
注:修改文件后要想马上生效还要运行$ source /home/guok/.bash_profile不然只能在下次重进此用户时生效。
变量赋值与引用(1-2) 变量追加(3-4) 变量实现动态命令(5-6):
[root@centos8 ~]#TITLE=cto
[root@centos8 ~]#echo "$TITLE"
cto
[root@centos8 ~]#TITLE+=:wang
[root@centos8 ~]#echo $TITLE
cto:wang
[root@centos8 ~]#CMD=hostname
[root@centos8 ~]#$CMD
centos8.magedu.com
查看所有环境变量: [root@bogon ~]# env
LS_COLORS是一个环境变量,用于定制ls命令在终端中显示的文件和目录的颜色。它可以让用户根据自己的需要来定义各种文件类型和目录的颜色,以便更好地区分它们。
LS_COLORS变量通常定义在shell的配置文件(例如.bashrc或.zshrc)中,并且可以通过修改这些文件来更改默认设置。
export 定义/ set 查看/ unset 删除环境变量
[root@bogon test.dir]# export mage="66666666handsome"
[root@bogon test.dir]# set | grep mage
_=mage
mage=66666666handsome
[root@bogon test.dir]# unset mage
[root@bogon test.dir]# echo "$mage"
declare 声明/ 赋值变量
declare -x 声明环境变量export declare -r 声明只读变量readonly declare -i 声明整数int
#声明并赋值
export name=VALUE
declare -x name=VALUE
四、只读变量,位置变量,软链接
《1》只读变量:只能声明定义,但后续不能修改和删除,即常量声明只读变量
[root@centos8 ~]#readonly PI=3.14159
[root@centos8 ~]#echo $PI
3.14159
后续PI变量不能进行修改和删除,都会报错!!
《2》位置变量
$1,$2,... #对应第1个、第2个等参数,shift [n]换位置
$0 #命令本身,包括路径
$* #传递给脚本的所有参数,全部参数合为一个字符串
$@ #传递给脚本的所有参数,每个参数为独立字符串
$# #传递给脚本的参数的个数
#注意:$@ $* 只在被双引号包起来的时候才会有差异
[root@centos8 ~]#vim test.ssh
echo "1st arg is $1"
echo "2st arg is $2"
echo "3st arg is $3"
echo "10st arg is ${10}"
echo "11st arg is ${11}"
echo "The number of arg is $#"
echo "All args are $*"
echo "All args are $@"
echo "The scriptname is `basename $0`"
[root@centos8 ~]#chmod +x test.ssh
[root@centos8 ~]#./test.ssh {a..z}
1st arg is a
2st arg is b
3st arg is c
10st arg is j
11st arg is k
The number of arg is 26
All args are a b c d e f g h i j k l m n o p q r s t u v w x y z
All args are a b c d e f g h i j k l m n o p q r s t u v w x y z
The scriptname is arg.sh
注:①用户可以在脚本中使用以下命令自定义退出状态码 exit [n]
②脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字
③如果exit后面无数字,终止退出状态取决于exit命令前面命令执行结果
④如果没有exit命令, 即未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一 条命令的状态码
《3》退出状态码变量
进程执行后,将使用变量$?保存状态码的相关数字 $? 取值0-255 0-成功 1-255失败
[root@centos8 ~]#curl -fs http://www.wangxiaochun.com >/dev/null
[root@centos8 ~]#echo $?
0
《4》展开命令行
把命令行分成单个命令词
展开别名
展开大括号的声明{}
展开波浪符声明 ~
命令替换$() 和 ``
再次把命令行分成命令词
展开文件通配符*、?、[abc]等等
准备I/0重导向 <、>
运行命令
防止扩展: ①'' # 单引号 ②"" #双引号 也可防止扩展,但是以下情况例外 $
变量扩展: ①`` #反引号,命令替换 ②$()#反引号,命令替换
③\ #反斜线,禁止单个字符扩展 ④! #叹号,历史命令替换
《5》 格式化输出printf命令
%s 字符串 %d ,%i 十进制数
%f 浮点格式 %c ASCII字符 显示对应参数的第一个字符
%b 相对应的参数中包含转义字符时,可以用此替换符进行替换,对应转移字符会被转义
%o 八进制 %u 不带正负的十进制值
%x 十六进制(a-f) %X 十六进制 (A-Z)
%% 表示%本身
一、输出命令echo
[root@localhost ~]# echo [选项] [输出内容] 输入的内容送往标准输出,输出的字符串间以空白符隔开,最后加上换行号
选项:
-e 支持反斜线控制的字符转换
-n 输出内容不换行
echo -e "\e[1;31mabcd \e[0m"
echo -e "\033[1 ; m…… \033[0m"
\e和\033输出效果相同 ,1 的位置是输出内容背景颜色,m 的位置是输出内容字体颜色,\033[0m 的位置是输出内容的属性
例:[root@localhost ~]# echo -e "\e[40;37m黑底白字 \e[0m"
黑底白字
echo命令还可显示复杂的输出格式
显示普通的字符串 [root@localhost ~]# echo "Hello Word!"
显示转义字符 [root@localhost ~]# echo "\Hello Word!\"
显示变量 [root@localhost ~]# name="abc"[root@localhost ~]# echo "you name is $name"
#!!注:再定义变量时,等号左右两侧不能有空格
显示换行 [root@localhost ~]# echo -e "Right!\n " # -e 表示开启转义
显示结果定向重定向至文件 [root@localhost ~]# echo "this is a test" > testfile
显示command命令执行结果 [root@localhost ~]# echo `date`
echo命令还有其他使用规则,可以通过man echo 进行查询
算术运算:
1. let var=expression let k=3
2. ((var=expression)) ((k=3))
3. var=$[expression] k=$[3] echo $k 输出3
4. var=$((expression))
5. var=$(expr arg1 arg2 ...)
6. declare -i var=number
7. echo expression|bc
[root@rocky86 0817]# i=1;j=4;
[root@rocky86 0817]# let k=i+j --->等价于 ((k=i+j)) 或 k=$[i+j]
[root@rocky86 0817]#echo $k
579
[root@rocky86 0817]# expr 10 \* 20
200
[root@rocky86 0817]# echo $[$RANDOM%50] --->RANDOM 随机数
6
编写第一个脚本
[root@localhost ~]# vim hello.sh # 创建并编辑叫hello的ssh脚本
#!/bin/bash
echo -e "This is a test"[root@localhost ~]# chmod +x hello.sh # 赋权限
[root@localhost ~]# ./hello.sh
二、历史命令
[root@localhost ~]# history [选项][历史保存文件]
选项:
-c 清空历史命令
-w 把缓存中的历史命令写入历史命令保存文件
~/.bash_history
历史命令的调用:
使用上、下箭头调用以前的历史命令
使用“!n”重复执行第n条历史命令
使用“!!”重复执行上一条命令
使用“!字串”重复执行最后一条以该字串开头的命令
三、命令别名
[root@localhost ~]# alias 别名='原命令'
[root@localhost ~]# alias #查询命令别名
[root@localhost ~]# vi /root/.bashrc #让别名永久生效
[root@localhost ~]# unalias 别名 # 删除别名
四、输入输出重定向
输出重定向!
①命令 > 文件 覆盖方式将命令的输出保存到指定文件中
②命令 >> 文件 追加方式将命令的输出保存到指定文件中
③命令 >文件 2>&1 或 命令 &>文件 覆盖方式将正确输出和错误输出都保存到同一个文件中
④命令 >>文件 2>&1 或 命令 &>>文件 追加方式将正确输出和错误输出都保存到同一个文件中
⑤命令 >>文件1 2>>文件2 追加方式将正确输出保存到文件1,错误输出保存到文件2
输入重定向!
[root@localhost ~]# wc [选项][文件名]
选项:
-c 统计字节数
-w 统计单词数
-l 统计行数
五、多命令顺序执行
①命令1;命令2 命令顺序执行,命令间无逻辑联系
②命令1 && 命令2 逻辑与, 命令1正确才会执行第二个命令
③命令1 || 命令2 逻辑或,命令1不正确才会执行第二个命令
④命令1 | 命令2 管道符: 命令1的正确输出作为命令2的操作对象
例:ll -a /etc/ | grep "proflile"
grep详解
[root@localhost ~]# grep [选项] “搜索内容” 文件名
选项:
-i 忽略大小写
-n 输出行号
-v 方向查找
--color=auto 搜索出的关键字用颜色显示
六、通配符
? 匹配任意一个字符
* 匹配0个或任意多个字符
[] 匹配中括号中任意一个字符 例 [abc] 可匹配a,b,c任意一个字符
[-] 匹配括号中任意一个字符 - 代表范围 例[0-9] 匹配一个数字 ll [0-9]abc 匹配abc之前有一个字符
[^] 逻辑非,匹配不是中括号里面的字符 例[^0-9] 匹配一个不是数字的字符 的文件
# 注释符
$ 用于调用变量的值
\ 转义符
[root@localhost ~]# name=abc
[root@localhost ~]# echo '$name'
[root@localhost ~]# echo "$name"
七、 Bash变量
解析:变量是计算机内存的单元,其中存放的值可以改变。当Shell脚本需要保存一些信息时,如一个文件名或是一个数字,就把它存放在一个变量中。
每个变量有一个名字,所以很容易引用它。使用变量可以保存有用信息,使系统获知用户相关设置,变量也可以用户保存暂时信息。
规则:
①变量名称可以由字母、数字和下划线组成,但不能以数字开头。
②变量的默认类型都是字符串型
③变量用等号连接值,等号左右两侧不能有空格。
④变量的值如果有空格,需要使用单引号或者双引号苦括起来。
⑤不能使用标点符号
<1>自定义变量:
#变量叠加
[root@localhost ~]# aaa=123
[root@localhost ~]# echo $aaa
[root@localhost ~]# aaa="$aaa"456
[root@localhost ~]# aaa="${aaa}"789
[root@localhost ~]# set ---->#变量查看
[root@localhost ~]# unset name ---->#变量删除
<2> 环境变量:主要保存的是和系统操作相关的数据
export 变量名=变量值 #申明变量
env #查询环境变量
unset 变量名 #删除变量
readonly 变量名 #设置成可读变量,不可删除
export name=test #将name变量名设置成环境变量
<3>位置参数变量:向脚本传递参数或数据的,变量名不可自定义,变量的作用是固定的
$n n为数字 $0代表命令本身 $1-$9代表第一到第九的参数 十以上的参数需要用大括号包含 ${10}
$* 这个变量代表命令行中所有的参数,所有的参数看成整体
$@ 代表命令行中所有的参数,每个参数区分对待
$# 代表命令行中所有参数的个数
举例:
[root@localhost ~]# vim canshu02.sh
#!/bin/bash
echo $0 #表示接受命令本身
echo $1 #接受第一个参数
echo $2 #接受第二个参数
[root@localhost ~]# chmod +x canshu02.sh
[root@localhost ~]# ./canshu02.sh 111 222 333
./canshu02.sh
111
222
333
[root@localhost ~]# vim canshu04.sh
#!/bin/bash
for i in "$*"
do
echo $i
donefor y in "$@"
do
echo $y
done
[root@localhost ~]# chmod +x canshu04.sh
[root@localhost ~]# ./canshu04.sh 111 222 333 444
111 222 333 444 --->$* 将所有参数看成一个整体,
111 --->$@传递每个参数区分对待
222
333
444
<4>预定义变量: 变量名不能自定义 变量作用也是固定的
$? 最后一次执行命令的返回状态。 为0--则表示上一个命令正确执行,非0--则表示上一个命令执行不正确
$$ 当前进程的进程号(PID)
$! 后台运行的最后一个进程的进程号(PID)
例:[root@localhost ~]# echo $?
<5!>接收键盘输入
[root@localhost ~]# read [选项][变量名]
选项:
-p "提示信息" 等待read输入时,输出提示信息
-t秒数 read命令一直等待用户输入,使用此选项可以指定等待时间
-n 字符数 read命令只接受指定的字符数,就会执行
-s 隐藏输入的数据,适用于机密信息的输入
[root@localhost ~]# read -t 30 -p "please input your name:" name # 提示后,等待30秒把用户输入保存到变量name中
[root@localhost ~]# echo "$name"
[root@localhost ~]# read -s -t 30 -p "please input your age:" age
[root@localhost ~]# echo -e "\n" # -e 表示隐藏输出的\n
[root@localhost ~]# echo "$age"
《6》间接变量引用: 如果第一个变量的值是第二个变量的名字,从第一个变量引用第二个变量的值就称为间接变量引用
方式1:
root@hjbog:~# var=name
root@hjbog:~# name=luck
root@hjbog:~# echo $var
name
root@hjbog:~# echo \$$var
$name
root@hjbog:~# eval echo \$$var
luck
方式2:
root@hjbog:~# tempvar=${!variable1} #变量赋值
root@hjbog:~# echo ${!variable1} #显示值
eval解析:
在SSH脚本中,"eval"命令的作用是将字符串作为Bash命令执行。具体来说,"eval"命令可以将一个包含变量和操作符等的字符串作为参数传递,并将其解析为有效的Bash命令。
这样一来,就可以动态地生成并执行不同的命令。
例如,以下示例脚本使用 "eval" 命令来执行变量 $COMMAND 中所存储的命令:
#!/bin/bash
HOST="example.com"
USER="myuser"
COMMAND="ls -la"
ssh $USER@$HOST "eval $COMMAND"
在上述脚本中,当脚本成功连接到远程主机后,会执行 "eval" 命令并带上包含在变量 $COMMAND 中的命令。
由于 "eval" 命令会将命令字符串解析为有效的 Bash 命令,因此最终会执行 "ls -la" 命令并返回结果。
需要注意的是,如果不能确保 $COMMAND 变量是来自可信的来源,或者包含恶意代码,那么使用 "eval" 命令可能存在安全风险。
《7》字符切片
${#var} #返回字符串变量var的字符的长度,一个汉字算一个字符
${var:offset} #返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始,到最后的部分,offset的取值在0 到 ${#var}-1 之间(bash4.2后,允许为负值)
${var:offset:number} #返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始,长度为number的部分
${var: -length} #取字符串的最右侧几个字符, 注意:冒号后必须有一空白字符
${var:offset:-length} #从最左侧跳过offset字符,一直向右取到距离最右侧lengh个字符之前的内容,即:掐头去尾
${var: -length:-offset} #先从最右侧向左取到length个字符开始,再向右取到距离最右侧. offset个字符之间的内容,注意:-length前空格,并且length必须大于offset
八、数值运算与运算符
<1> 数字运算
declare声明变量类型
[root@localhost ~]# declare [+/-][选项]变量名
选项:
- 给变量设定类型属性
+ 取消变量的类型属性
-i 将变量声明为整数型(integer)
-x 将变量声明为环境变量
-p 显示指定变量的被声明的类型
root@hjbog:~# a=111
root@hjbog:~# b=222
root@hjbog:~# declare -i f=$a+$b
root@hjbog:~# echo "$f"
333
root@hjbog:~# c=$(( $a+$b))
root@hjbog:~# echo "$c"
333
root@hjbog:~# d=$[ $a+$b ]
root@hjbog:~# echo "$d"
333
root@hjbog:~# e=$(expr $a + $b )
root@hjbog:~# echo "$e"
333
<2> 运算符
https://img-blog.csdnimg.cn/img_convert/dfda5956c30480714dff48ab902a4f01.png
<3>变量测试与内容替换
https://img-blog.csdnimg.cn/img_convert/36dce2c070719bf3530ba82eaca65ec0.png
root@hjbog:~# unset y
root@hjbog:~# x=${y-new}
root@hjbog:~# echo $x
new
root@hjbog:~# x=${y=ne}
root@hjbog:~# echo $x $y
ne ne
《4》 数组
普通数组可以不事先声明,直接使用: declare -a ARRAY_NAME
关联数组必须先声明,再使用: declare -A ARRAY_NAME数组赋值:
[root@rocky86 ~]# weekdays[0]="Sunday"
[root@rocky86 ~]# title=('name','age','grade')
[root@rocky86 ~]# echo $title
显示所有数组: declare -a
引用数组:
[root@rocky86 ~]# declare -a title=([0]="name" [1]="age")
[root@rocky86 ~]# echo ${title[1]}root@hjbog:~# title=('name','age')
root@hjbog:~# echo $title
name,age
root@hjbog:~# declare -a title1=([0]="luck",[1]="love")
root@hjbog:~# echo $title1[1]
luck,[1]=love[1]
root@hjbog:~# echo ${title1[0]}
luck,[1]=love
引用数组所有元素:
${ARRAY_NAME[*]} 或 ${ARRAY_NAME[@]}
root@hjbog:~# arr=({a..e})
root@hjbog:~# for i in ${arr[*]};do echo $i; done;
a
b
c
d
e
root@hjbog:~# num=({0..10})
root@hjbog:~# echo $num
0
root@hjbog:~# echo ${num[*]}
0 1 2 3 4 5 6 7 8 9 10
数组的长度--数组中元素的个数
root@hjbog:~# echo ${#num[*]}
11
列出数组所有的下标
root@hjbog:~# echo ${!num[@]}
0 1 2 3 4 5 6 7 8 9 10
删除数组
root@hjbog:~# unset num[10]
root@hjbog:~# echo ${num[*]}
0 1 2 3 4 5 6 7 8 9
关联数组: 关联数组要先声明才可以使用,关联数组可以自定义下标,普通数组必须用数字、、
声明如下:
declare -A ARRAY_NAME
ARRAY_NAME=([idx_name1]='val1' [idx_name2]='val2‘...)
root@hjbog:~# declare -A test
root@hjbog:~# test[a]='all'
root@hjbog:~# echo ${test[a]}
all
root@hjbog:~# test[b]='value'
root@hjbog:~# for i in ${!test[*]};do echo ${test[$i]};done
all
value
root@hjbog:~# for i in ${test[*]};do echo ${i};done
all
value
九、配置文件 :环境变量配置文件中主要是定义对系统的操作环境生效的系统默认环境变量(例:PATH,HISTSIZE,PSI,HOSTNAME)
<1>source命令
[root@localhost ~]# source 配置文件
[root@localhost ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@localhost ~]# PATH="$PATH":/root #这样设置只是临时生效,下次重启后就失效了
[root@localhost ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root
系统上面的配置文件目录
①/etc/profile #其中的配置是对所有登录过系统的用户生效
/etc/profile的作用: USER变量 LOGNAME变量 MAIL变量 PATH变量
HOSTNAME变量 HISTSIZE变量 umask
调用/etc/profile.d/*.sh文件
②/etc/profile.d/*.sh #其中的配置是对所有登录过系统的用户生效
③~/.bash_profile #对当前用户配置生效
④~/.bashrc #对当前用户配置生效
⑤/etc/bashrc #其中的配置是对所有登录过系统的用户生效
~/.bash_profile的作用: ①调用~/.bashrc文件 ②在PATH变量后加入了“:$HOME/bin”这个目录
转义符: https://img-blog.csdnimg.cn/img_convert/e3434ca1f95f1d38fba78ef634ad3695.png
十、正则表达式与通配符
正则表达式: 用来在文件中匹配符合条件的字符串,正则是包含匹配。支持正则的命令:grep,awk,sed 不支持正则的命令:ls,find,cp
通配符:用来匹配条件的文件名,通配符就是完全匹配。
基础正则表达式:https://img-blog.csdnimg.cn/img_convert/2fdef691494b1d6dbc453deded63b91e.png
举例:
①“*”前一个字符匹配0次或者任意多次
[root@localhost ~]# grep "a*" test.txt #匹配所有的内容,包括空白行
[root@localhost ~]# grep "aa*" test.txt #匹配至少包含一个a的行
[root@localhost ~]# grep "aaa*" test.txt #匹配至少包含两个连续a的行②"."匹配除了换行符外任意一个字符
[root@localhost ~]# grep "s..d" test.txt #s..d 会匹配在s和d这两个字母之间一定有两个字符的单词
[root@localhost ~]# grep "s.*d" test.txt #匹配在s和d字母之前有任意字符
[root@localhost ~]# grep ".*" test.txt #匹配所有内容③"^" 匹配行首,“$” 匹配行尾
[root@localhost ~]# grep "^A" test.txt #匹配以大写字母A开头的行
[root@localhost ~]# grep "b$" test.txt #匹配以小写字母b开头的行
[root@localhost ~]# grep "^$" test.txt #匹配空白行④[ ]”匹配中括号中指定的任意一个字符,只匹配一个字符
[root@localhost ~]# grep "a[bc]de" test.txt #匹配a和d字母中,要么是b、要么是c
[root@localhost ~]# grep "[0-9]" test.txt #匹配任意一个数字
[root@localhost ~]# grep "^[a-z]" test.txt #匹配用小写字母开头的行⑤"[^]" 匹配除中括号的字符以外的任意一个字符
[root@localhost ~]# grep "^[^0-9]" test.txt 匹配不用数字开头的行
[root@localhost ~]# grep "^[^a-zA-Z] test.txt 匹配不用字母开头的行⑥"\{n\}" 表示前面的字符恰好出现n次
[root@localhost ~]#grep "a\{3\}" test.txt 匹配a字母连续出现三次的字符串
[root@localhost ~]#grep "[0-9]{3\}" test.txt 匹配包含联系的三个数字的字符串⑦"\{n,\}" 表示其前面的字符出现不小于n次
[root@localhost ~]#grep "[0-9]{3,\}" test.txt 匹配最少用三个连续数字开头的行⑧"\{n,m\}" 匹配其前面的字符至少出现n次,最多出现m次
[root@localhost ~]#grep "ab\{1,3\}g" test.txt 匹配在字母a和g之前有至少一个b,至多3个b
十一、字符串截取命令
① cut字段提取命令
[root@localhost ~]# cut [选项] 文件名
选项: -f 列号:提取第几列 -d 分隔符:按照指定分隔符分割列
例: [root@localhost ~]# cut -d ":" -f 1 /etc/passwd #截取/etc/passwd下面,指定分隔符为“:”,第一列的所有用户名
注意: cut不能作用于空格作为分隔符,并提取数据,只能用作制表符提取字符。
②printf命令
printf '输出类型输出格式' 输出内容
输出类型: %ns 输出字符串 n-数字,指输出的几个字符
%ni 输出整数 n-数字,指输出几个数字
%m.nf 输出浮点数 m,n-数字,指输出的整数位和小数位数。 例:%3.2f-->共输出5位数,3位整数,2位小数
输出格式: \a 输出警告声音 \b 输出退格键
\f 清除屏幕 \n 换行
\r 回车 \t 水平输出退格键
\v 垂直输出退格键
③awk命令 格式: awk '条件1{动作1} 条件2{动作2}...' 文件名
条件:一般使用关系表达式作为条件 动作:格式化输出 流程控制语句
例:[root@localhost ~]# df -h | awk '{print $1 "\t" $5 "\t" $6}' #打印提取第一列,第5列和第六列,并且以制表符分割开
[root@localhost ~]# awk 'BEGIN{FS=":"}{print $1 "\t" $3}' /etc/passwd # FS内置变量
④ sed命令 : 将数据进行选取,替换,删除,新增的命令
[root@localhost ~]# sed [选项] '[动作]' 文件名
选项:
-n 一般sed命令会把所有数据都输出到屏幕,如果加入此选项,则只会把经过sed命令处理的行输出到屏幕。
-e 允许对输入数据应用多条sed命令编辑
-i 用sed的修改结果直接修改读取数据的文件,而不是由屏幕输出
动作: a\ 追加,在当前行后添加一行或多行。添加多行时,除最后一行外,每行末尾需要用“\”代表数据未完结
c\ 行替换,用c后面的字符串替换
i\ 插入,在当期行前拆入一行或多行。插入多行时,除最后一行外,每行末尾需要用‘\’代表数据未完结
d 删除,删除指定行
p 打印,输出指定行
s 字符串替换,用一个字符串替换另外一个字符串。格式:“行范围s/旧字符串/新字串/g”
[root@localhost ~]#sed '2p' test.txt 查看文件第二行,打印所有数据
[root@localhost ~]#sed -n '2p' test.txt 只查看第二行数据
[root@localhost ~]#sed '2,4d' test.txt 删除第二到第三行的数据,但不修改文件本身
[root@localhost ~]#sed '3a hello' test.txt 在第三行后追加hello
字符串替换: [root@localhost ~]# sed '3s/abc/cde/g' test.txt 在第三行中,把abc换成de
[root@localhost ~]#sed -i '3s/abc/cde/g' test.txt 直接将数据写入文件
[root@localhost ~]# sed -e 's/abc//g;s/def//g' test.txt 同时将数据修改为空
十二、条件判断 --文件
《1》文件运算符
-b 文件 判断文件是否为块设备文件 ,若是则返回真
-c 文件 判断文件是否未字符设备文件,如果是,则返回真
-d 文件 判断该文件是否为目录文件,如果是,则返回真
-e文件 判断该文件是否存在,若存在,则返回真
-f文件 判断该文件是否为普通文件,如果是,则返回真
-L 文件 判断该文件是否为符号链接文件,如果是则返回真
-p文件 判断文件是否为管道文件,如果是,则返回真
-s文件 判断该文件是否为套接字文件,如果是则返回真
-r/-w/-x文件 判断该文件是否可读 /可写 /可执行 如果是则返回真
-u/-g/-k文件 判断文件是否拥有SUID/SGID/SBit--特殊权限命令,如果是则返回真 详解:http://www.ciscoedu.com.cn/details/id/266.html
[root@localhost ~]#test -e /root/test.yaml 格式判断
[root@localhost ~]#[-e /root/test.yaml]
[root@localhost ~]#[ -d /root ] && echo 'yes' || echo 'no' 第一个判断命令如果正确执行,则打印yes,否则打印no
[root@localhost ~]#[-w /root/dash.yaml] && echo 'yes' || echo 'no' 判断文件是否有可写的权限
《2》两个文件间比较
filename1 -nt filename2 判断文件1的修改时间是否比文件2的新,如果新则返回真
filename1 -ot filename2 判断文件1的修改时间是否比文件2的旧,如果旧则返回真
filename1 -ef filename2 判断文件1是否和文件2的inode号一致(两个文件是否为同一个文件),可用于判断硬链接
举例:[root@localhost ~]# [ /root/dash.yaml -ef /tmp/dash.yaml ] && echo yes || echo no
《3》 整数比较
整数1 -eq 整数2 判断整数1是否和整数2相等,相等则返回真
整数1 -ne 整数2 判断整数1是否和整数2不相等,不相等则返回真
整数1 -gt 整数2 判断整数1是否大于整数2,大于则返回真
整数1 -lt 整数2 判断整数1是否小于整数2,小于则返回真
整数1 -ge 整数2 判断整数1是否大于整数2,大于等于则返回真
整数1 -le 整数2 判断整数1是否小于等于整数2,小于等于则返回真
《4》字符串判断
-z 字符串 判断字符串是否为空,为空则返回真
-n 字符串 判断字符串是否为非空,非空则返回真
字符串1 == 字符串2 判断两字符串是否相等,相等则真
字符串1 != 字符串2 判断两字符串是否不想打,不相等则返回真
校对字符串 参考链接: https://www.cnblogs.com/-courage/p/16665747.html
《5》 多重条件判断
判断1 -a 判断2 逻辑与,判断1与判断2都成立,结果为真
判断1 -o 判断2 逻辑或,判断1和判断2任一成立,结果为真
!判断 逻辑非,使原始的判断式取反
[root@localhost ~]# name=sc
[root@localhost ~]# name1=sc
[root@localhost ~]# [ -n "$name"] && echo yes || echo no 输出yes
[root@localhost ~]# [ "$name1" == "$name" ] && echo yes || echo no 输出yes
例:
[root@localhost ~]# aa=24
[root@localhost ~]# [ -n "$aa" -a "$aa" -gt 23 ] && echo yes || echo no
yes
[root@localhost ~]# [ -n "$aa" -a "$aa" -ge 24 ] && echo yes || echo no
yes
[root@localhost ~]# [ -n "$aa" -a "$aa" -ge 25 ] && echo yes || echo no
no
[root@localhost ~]# [ -n "$name" -o -z "$name1" ] && echo yes || echo no
yes
十三、流程控制
《1》if 条件语句
if [条件判断];then
程序
fi
if [条件判断]
then
程序
fi
《2》if else 条件语句
if [条件判断]
then
条件成立时,执行此程序
else
条件不成立时,执行的另外一个程序
fi
例:
#同步系统时间
ntpdate asia.pool.ntp.org &>/dev/null
#把当前系统时间按照“年月日”格式赋予变量date
date=$( date+%y%m%d )
#统计mysql的数据库大小,并把大小赋予size变量
size=$( du -sh /var/lib/mysql )
if [ -d /tmp/dbback ]
then
echo "Date: $date!" > /tmp/dbback/dbinfo.txt
echo "Date size: $size" >> /tmp/dbback/dbinfo.txt
cd /tmp/dbback
tar -zcf mysql-lib-$date.tar.gz /var/lib/mysql dbinfo.txt &>/dev/null
rm -rf /tmp/dbback/dbinfo.txt
else
mkdir /tmp/dbback
echo "Date: $date!" > /tmp/dbback/dbinfo.txt
echo "Date size: $size" >> /tmp/dbback/dbinfo.txt
cd /tmp/dbback
tar -zcf mysql-lib-$date.tar.gz /var/lib/mysql dbinfo.txt &>/dev/null
rm -rf /tmp/dbback/dbinfo.txt
fi
例:
[root@localhost ~]# vim test1.sshecho "如果想去上班,请输入1"
echo "如果不想上班,请输入2"
echo "如果想居家办公,请输入3"
read -t 30 -p "请输入你的选择:" choose
case "$choose" in
"1")
echo "想去上班!"
;;
"2")
echo "不想去上班!"
;;
"3")
echo "居家办公!"
;;
*)
echo "只能输入1或者2或者3"
;;
esac
[root@localhost ~]# chmod +x test1.ssh #赋予权限 否则报错:-bash: ./test1.ssh: Permission denied
[root@localhost ~]# ./test1.ssh
《2》for 循环
for 变量 in 值1 值2 值3
do
程序
done
for ((初始值; 循环控制条件; 变量变化))
do
程序
done
例: for i in 1 2 3 4 5
do
echo $i
done
九九乘法表:
for((i=1;i<10;i++));do
for((j=1;j<=i;j++));do
echo -e "${j}x$i=$((j*i))\t\c"
done
echo
doneread -t 30 -p "Please input user name:" name
read -t 30 -p "Please input the mumber of users:" num
read -t 30 -p "Please input the password of users:" pass
if [ ! -z "$name" -a ! -z "$num" -a ! -z "$pass" ]
then
y=$(echo $num | sed 's/[0-9]*$'//g)
if [ -z "$y" ]
then
for (( i=1;i<=$num;i=i+1 ))
do
/usr/sbin/useradd $name$i &>/dev/null
echo $pass | /usr/bin/passwd --stdin $name$i &>/dev/null
done
fi
fi
《3》 while循环:条件循环,只要条件判断式成立,循环就会一直继续,直到条件判断式不成立,循环才停止。
while [条件判断式]
do
程序
done
例: 从1加到100
i=1
s=0
while [ $i -le 100]
do
s=$(($s+$i))
i=$(($i+1))
done
echo "the sum is: $s"
《4》unit循环:与while循环相反,只要判断式不成立,则进行循环,执行循环程序,若条件成立,则终止循环
i=1
s=0
unit [ $i -gt 100]
do
s=$(($s+$i))
i=$(($i+1))
done
echo "the sum is : $s"
十四、控制语句
《1》continue
continue[N] 提前结束第N层的本轮循环,直接进入下一轮判断,最内层为第一层
格式:
while CONDITION1;
do
CMD1
...
if CONDITION2;
then
continue
fi
CMDn
...
done
《2》 循环控制语句 break
brak n 跳出n层
while CONDITION1;
do
CMD1
...
if CONDITION2;
then
break
fi
CMDn
...
done
《3》循环控制shift命令
shift [n] 用于将参量列表 list 左移指定次数,缺省为左移一次。
参量列表 list 一旦被移动,最左端的那个参数就从列表中删除。
until [ -z "$1" ]; do
echo "$@ "
shift
done
[root@rocky86 ~]# bash s.sh a b c d e f g
a b c d e f g
b c d e f g
c d e f g
d e f g
e f g
f g
g
十五、函数 function
函数 function 是由若干条shell命令组成的语句块,实现代码重用和模块化编程。
它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部分。
#语法一
func_name(){
...函数体...
}
#语法二
function func_name {
...函数体...
}
#语法三
function func_name(){
...函数体...
}
declare -F #查看当前已定义的函数名
declare -f #查看当前已定义的函数定义
declare -f func_name #查看指定当前已定义的函数名
declare -F func_name #查看当前已定义的函数名定义
unset func_name # 删除函数
函数返回值:函数默认返回值是函数体中最后一条命令的退出状态码; 也可以使用return 自定义函数的返回值,在函数中使用 return,return 之后的语句将不会被执行。
return 0 无错误返回 return 1-255 有错误返回。
return 与 exit的区别: ①return 只会中断函数执行,但exit 会中断整个脚本的执行。
②在方法中,若自定义返回值,则return 之后的语句将不会被执行。
《2》 环境函数--使子进程也可使用父进程定义的函数
声明定义环境函数: export -f function_name declare -xf function_name
查看环境函数: export -f declare -xf
《3》 函数递归 : 函数直接或间接调用自身,注意递归层数,及不能陷入死循环。
例: 递归实现阶乘
fac(){
if [ $1 -gt 1 ];then
echo $[$1 * $(fac $[$1-1])]
else
echo 1
fi
}fac $1
[root@rocky86 ~]# bash fac.sh 5
12
十六、信号捕捉工具
trap 命令可以捕捉信号,修改信号原来的功能,实现自定义功能 在脚本或程序的执行过程中,
我们可以通过发送信号的方式,打断或终止程序的执行过程,为了避免这 种情况,我们可以使用信号捕捉,来自定义信号处理。
trap [-lp] [[arg] signal_spec ...]
#常用选项: ①-l #显示所有信号 ②-p #显示所有自定义的信号
例:
trap 'command' signal #自定义指定信号的处理方式
trap '' signal #忽略指定的信号
trap '-' signal #恢复信号默认操作
trap func EXIT #退出时执行func
表示信号的三种方式:3) SIGQUIT
3 #信号ID
SIGQUIT #完整写法,大小写都支持
QUIT #简短写法,大小写都支持
编写脚本遇到的问题:
1. SSH登录BMC : 为什么显示命令失败result=$(sshpass -p $bmc_superpwd ssh -o StrictHostKeyChecking=no $bmc_superuser@bmc_ip)
①输入的 BMC 用户名、IP 地址或密码不正确,或者 SSH 服务未启动或设置不正确。请确保您已正确输入有关 BMC 的所有信息,并检查是否可以通过手动 SSH 登录到 BMC。
②sshpass 命令未正确安装或配置。解决:apt install sshpass
2.在shell脚本中,第一部分就应该定义变量,且定义变量时,等号左右两边不能有空格 例: name=lily
3.执行IPMI命令时,一定要采用正确格式:$(IPMI命令)
status=$(ipmitool -I lanplus -H $bmc_ip -U $bmc_user -P $bmc_pwd raw 0x06 0x52 0x17 0x20 0x01 0x01 0x42)
4. shell脚本中的时间等待: sleep n ---n为秒数
5. shell脚本定义数组:
declare -A status_code=(
["on"]="ff"
["off"]="00"
["twikcle"]="04"
)
获取数组的值: ${status_code["on"]}
if语句校对数组的值 格式: if ["${status_code[$1]}" == "$2"];then
数组参考链接: https://zhuanlan.zhihu.com/p/483399604