Shell基础
Shell基础
Bash注释
-
Bash只支持单行注释,使用
#
开头的都被当作注释语句# 单行注释 echo "Hello World" #注释
-
通过Bash特性,可以实现多行注释
:' 注释 ' : <<'EOF' 注释 EOF
Bash基本数据类型
-
Bash中基本数据类型只有字符串类型,连数值类型都没有
# 都是字符串类型,可用declare -i声明为数值类型 [root@localhost ~]# echo hello [root@localhost ~]# echo 123
Bash字符串串联
-
Bash中字符串的串联操作,可用将两段数据连接在一起
[root@localhost ~]# echo xiaowang xiaowangc xiaowang xiaowangc [root@localhost ~]#
变量赋值和引用变量
[root@localhost ~]# a=xiaowangc
[root@localhost ~]# echo $a
xiaowangc
[root@localhost ~]#
-
Shell可用使用未定义的变量和使用空变量
[root@localhost ~]# echo $abc [root@localhost ~]# a= [root@localhost ~]# echo $a [root@localhost ~]#
-
变量引用
[root@localhost ~]# a=666 [root@localhost ~]# echo $a 777 666 777 [root@localhost ~]#
命令替换
-
命令替换是值先执行id root,将id root的输出结果替换到$()
[root@localhost ~]# echo $(id root) uid=0(root) gid=0(root) groups=0(root)
算数运算
-
Shell可用使用$[]和$(())和let命令做算数运算
[root@localhost ~]# a=10 [root@localhost ~]# echo $[a+3] 13 [root@localhost ~]# echo $((a+3)) 13 [root@localhost ~]# echo $((1+1)) 2 [root@localhost ~]# let a+3 [root@localhost ~]# let a=a+3 [root@localhost ~]# echo $a 13
退出状态码
每个命令执行之后都有对应的进程退出状态码,用来表示该进程是否正常退出。所以,在Shell中经常会使用特殊变量$?判断前台命令是否正常退出。
- 如果$?的值为:
- 为0,表示进程成功执行,即正常退出
- 非0,表示进程未成功执行,即非正常退出
- 非0退出状态码不一定表示错误,也可能是逻辑上正常的退出
- 在Shell脚本中,所有条件判断(比如if语句、while语句)都以0退出状态码表示True,以非0退出状态码表示False
Exit命令
exit命令可用于退出当前Shell进程。退出Shell终端、脚本等。
$ exit
后台执行命令&
在命令的结尾使用&符号,表示将这个命令放入后台执行。
[root@localhost ~]# sleep 20 &
[root@localhost ~]# echo $!
多命令组合
Shell中有多种组合多个命令的方式
-
分号
[root@localhost ~]# echo xiaowangc ; echo hello xiaowangc hello [root@localhost ~]#
-
&&
前者正确执行完毕并正常退出后,执行后者命令
[root@localhost ~]# echo xiaowangc && echo hello xiaowangc hello [root@localhost ~]#
-
||;如果前者正确只执行前者,前者不正确执行后者(或)
[root@localhost ~]# ping asdf && ping www.baidu.com [root@localhost ~]# ping -c 4 www.baidu.com || ping abc
-
逻辑结合
# 命令1 && 命令2 && 命令3... 如果命令1正确执行则执行命令2,如果命令2正确执行则执行命令3 # 命令1 && 命令2 || 命令3... 如果命令1正确执行则执行命令2,如果命令1不正确执行则执行命令3 如果命令1正确执行则执行命令2,如果命令2不正确执行则执行命令3 # 命令1 || 命令2 && 命令3... 如果命令1正确执行则执行命令3 如果命令1不正确执行则执行命令2,如果命令2正确执行则执行命令3
多个命令组合
-
通过小括号或者大括号组合多个命令
(命令1 ; 命令2 ; 命令3) # 小括号是在子Shell中执行 { 命令1 ; 命令2 ; 命令3} { 命令1 命令2 命令3 } # 大括号当前Shell中执行
重定向
标准输入、标准输出、标准错误,在Linux系统中,每个程序默认都会打开三个文件描述符
- fd=0:标准输入
- fd=1:标准输出
- fd=2:标准错误
Linux中一切皆文件,文件描述符也是文件:
- fd = 0:对应/dev/stdin文件
- fd = 1:对应/dev/stdout文件
- fd = 2:对应/dev/stderr文件
[root@localhost ~]# ls -l /dev/std*
lrwxrwxrwx. 1 root root 15 May 3 04:28 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx. 1 root root 15 May 3 04:28 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx. 1 root root 15 May 3 04:28 /dev/stdout -> /proc/self/fd/1
[root@localhost ~]#
重定向操作
1. > #格式化输出
2. >> #追加输出
3. < #输入重定向
4. &> #特殊重定向,将标准错误和标准输出都重定向到指定的File中,等价于>file 2>&1
5. &>> #特殊重定向,将标准错误和标准输出都追加到指定File中,等价于>>file 2>&1
还有一种操作经常将输出的目标文件指定为/dev/null。它是空设备,
cat /dev/null > file #清空文件
cat命令
[root@localhost ~]# cat -n /etc/fstab #-n选项,输出时带行号
1
2 #
3 # /etc/fstab
4 # Created by anaconda on Sun May 2 20:23:48 2021
5 #
6 # Accessible filesystems, by reference, are maintained under '/dev/disk/'.
7 # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
8 #
9 # After editing this file, run 'systemctl daemon-reload' to update systemd
10 # units generated from this file.
11 #
12 /dev/mapper/cl-root / xfs defaults 0 0
13 UUID=ffc9c9ba-0b05-43c3-8241-e19518b8c840 /boot ext4 defaults 1 2
14 /dev/mapper/cl-swap swap swap defaults 0 0
[root@localhost ~]# cat < /etc/fstab
#
# /etc/fstab
# Created by anaconda on Sun May 2 20:23:48 2021
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
/dev/mapper/cl-root / xfs defaults 0 0
UUID=ffc9c9ba-0b05-43c3-8241-e19518b8c840 /boot ext4 defaults 1 2
/dev/mapper/cl-swap swap swap defaults 0 0
[root@localhost ~]#
here docer
输入重定向是<,除此之外还有<<,<<<
-
<<符号表示here doc,也就是后面表示跟着的是一篇文档。常用于多行数据输入
[root@localhost ~]# cat << EOF #here doc作为标准输入被读取,然后被cat输出 > hello > xiaowangc > EOF hello xiaowangc [root@localhost ~]# cat << EOF > xiaowangc.txt #here doc的内容还会被cat格式化输出到指定文档 > hello > xiaowangc > EOF [root@localhost ~]# cat xiaowangc.txt hello xiaowangc [root@localhost ~]#
-
<<<表示here string。也就是说该符号后面是一个字符串
[root@localhost ~]# cat <<< xiaowangc xiaowangc [root@localhost ~]# a=11111 [root@localhost ~]# cat <<< $a 11111 [root@localhost ~]# cat <<< "xiaowangc$a" #使用双引号时会进行替换 xiaowangc11111 [root@localhost ~]# cat <<< 'xiaowangc$a' #使用单引号时不会进行替换 xiaowangc$a [root@localhost ~]#
管道
每一个竖线”|“代表一个管道,第一个命令的标准输出会放进管道,第二个命令会从管道中读取进行处理
[root@localhost ~]# ps -aux | grep sshd
root 1005 0.0 0.5 92968 4280 ? Ss May08 0:00 /usr/sbin/sshd -D -oCiphers=aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,aes256-ctr,aes256-cbc,aes128-gcm@openssh.com,aes128-ctr,aes128-cbc -oMACs=hmac-sha2-256-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha1,umac-128@openssh.com,hmac-sha2-512 -oGSSAPIKexAlgorithms=gss-gex-sha1-,gss-group14-sha1- -oKexAlgorithms=curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1 -oHostKeyAlgorithms=rsa-sha2-256,rsa-sha2-256-cert-v01@openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384,ecdsa-sha2-nistp384-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-512-cert-v01@openssh.com,ecdsa-sha2-nistp521,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,ssh-rsa,ssh-rsa-cert-v01@openssh.com -oPubkeyAcceptedKeyTypes=rsa-sha2-256,rsa-sha2-256-cert-v01@openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384,ecdsa-sha2-nistp384-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-512-cert-v01@openssh.com,ecdsa-sha2-nistp521,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,ssh-rsa,ssh-rsa-cert-v01@openssh.com -oCASignatureAlgorithms=rsa-sha2-256,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,rsa-sha2-512,ecdsa-sha2-nistp521,ssh-ed25519,ssh-rsa
root 55071 0.0 1.2 152904 9960 ? Ss 05:23 0:00 sshd: root [priv]
root 55085 0.0 0.6 152904 5060 ? S 05:23 0:00 sshd: root@pts/0
root 58868 0.0 0.1 12112 1040 pts/0 R+ 07:35 0:00 grep --color=auto sshd
[root@localhost ~]#
让grep既从/etc/fstab读取数据,也从管道中读取数据
[root@localhost ~]# ps aux | grep "#" /etc/fstab /dev/stdin
/etc/fstab:#
/etc/fstab:# /etc/fstab
/etc/fstab:# Created by anaconda on Sun May 2 20:23:48 2021
/etc/fstab:#
/etc/fstab:# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
/etc/fstab:# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
/etc/fstab:#
/etc/fstab:# After editing this file, run 'systemctl daemon-reload' to update systemd
/etc/fstab:# units generated from this file.
/etc/fstab:#
/dev/stdin:zabbix 19079 0.0 0.3 76692 2584 ? S May08 0:00 /usr/sbin/zabbix_agentd: listener #1 [waiting for connection]
/dev/stdin:zabbix 19080 0.0 0.3 76692 2592 ? S May08 0:00 /usr/sbin/zabbix_agentd: listener #2 [waiting for connection]
/dev/stdin:zabbix 19081 0.0 0.3 76692 2672 ? S May08 0:00 /usr/sbin/zabbix_agentd: listener #3 [waiting for connection]
/dev/stdin:zabbix 19082 0.0 0.3 76692 2848 ? S May08 0:04 /usr/sbin/zabbix_agentd: active checks #1 [idle 1 sec]
/dev/stdin:root 58944 0.0 0.1 12112 1000 pts/0 R+ 07:38 0:00 grep --color=auto # /etc/fstab /dev/stdin
[root@localhost ~]#
tee命令
tee命令可以将标准输入复制到标准输出和0或多个文件中。tee的作用是数据多重定向
[root@localhost ~]# echo hello | tee /tmp/xiaowangc /tmp/xiaowc | cat
hello
条件测试语句
test命令或Bash内置命令[ ]可以做条件测试,如果测试的结果为True,则退出的状态码为0
这些条件测试常用在if、while语句中
-
true和false命令
true命令返回true,退出码为0
false命令返回false,退出码非0
[root@localhost ~]# true [root@localhost ~]# echo $? 0 [root@localhost ~]# false [root@localhost ~]# echo $? 1 [root@localhost ~]#
-
文件类测试
条件表达式 含义 -e 判断文件是否存在 -f 判断文件是否存在且为普通文件 -b 判断文件是否存在且为块设备 -c 判断文件是否存在且为字符设备 -S 判断文件是否存在且为套接字文件 -p 判断文件是否存在且为命令管道文件 -l 判断文件是否存在且为一个链接文件 -d 判断文件是否存在且为普通目录 -
文件属性类测试
条件表达式 含义 -r 文件是否存在且当前用户可读 -w 文件是否存在且当前用户可写 -x 文件是否存在且当前用户可执行 -s 文件是否存在且为非空文件 -N 文件是否存在,且上次read后是否被modify -
两个文件之间的比较
条件表达式 含义 file1 -nt file2 判断file1是否比file2新 file1 -ot file2 判断file1是否比file2旧 file1 -ef file2 判断file1与file2是否为同一文件 -
数值大小比较
条件表达式 含义 int1 -eq int2 两个数值相等 int1 -ne int2 两个数值不相等 int1 -gt int2 n1大于n2 int1 -lt int2 n1小于n2 int1 -ge int2 n1大于等于n2 int1 -le int2 n1小于等于n2 -
字符串比较
条件表达式 含义 -z str 判断字符串是否为空,返回true str or -n str 判断字符串是否为空,返回falsh str1 = str2 or str1 == str2 判断str1和str2是否相同,相同则返回true str1 != str2 判断str1是否不等于str2 str1 > str2 判断str1是否大于str2 str1 < str 判断str1是否小于str2 -
逻辑运算符
条件表达式 含义 -a or && 两表达式同时为true才为true -o or || 两表达式任何一个为true则为true ! 对表达式取反 () 更改表达式优先级
if语句
if 条件判断式1; then
#当条件满足时,执行的语句
语句;
[elif 条件判断式2; then
#当条件满足时,执行的语句;]
[else 所有条件不成立时,执行此语句;]
fi
#test-commands既可以是test测试或[]、[[]]测试,也可以是任何其他命令,test-commands用于条件测试,它只判断命令的退出状态码是否为0,为0则为true
实例:
#! /bin/sh
dir_d=/media/disk_d #定义了三个变量
dir_e=/media/disk_e
dir_f=/media/disk_f
a=`ls $dir_d | wc -l` #将ls和wl命令运行的返回值赋值给a、b、c
b=`ls $dir_e | wc -l`
c=`ls $dir_f | wc -l`
echo "检查 disk_d.."
if [ $a -eq 0 ]; then #判断$a变量是否等于0,等于0则代表不存在
echo "disk_d 不存在,现在开始创建..."
sudo mount -t ntfs /dev/disk/by-label/software /media/disk_d #挂载
else
echo "disk_d 存在"
fi
case
case用于确定的分支判断。
实例:
#! /bin/bash
case $a in
"1")
#执行此语句
;;
"2")
#执行此语句
;;
*)
#如果都不满足则执行此语句
;;
esac
#case以case开头,以esac结尾
#在每个分支后面都要以;;结尾
for循环
两种for循环结构:
#第一种
for i in s1 s2 s3 ...;do 语句;done
for i in s1 s2 s3;do
语句
done
#第二种
for ((初始化;循环控制条件;变量变化));
do
语句
done
while循环
while 测试条件;
do
语句
done
无限循环的写法
while :
do
命令
done
while true
do
命令
done
Shell函数
Shell函数可以当作命令一样执行,它是一个或多个命令的组合结构体。
#Shell函数的几种语法格式
function 函数名 { 命令 }
函数名() { 命令 }
function 函数名() { 命令 }
函数定义后,可以直接使用函数名来进行调用,同时可以向函数传递0个或多个参数
#不传递参数
函数名
#传递多个参数
函数名 参数1 参数2 参数3 ...
- 在函数中,那些位置变量将具有特殊的含义:
- $1、$2、$3...:传递给函数的第一个参数保存在$1中,第二个参数保存在$2中,以此类推
- $@、$*:保存所有参数,各参数使用空格分隔
- 不用双引号包围时,两者没区别
- 使用双引号包围时,$@的各个元素都被双引号包围,$*的所有元素一次性被双引号包围
local在函数里定义局部变量
return语句可以来定义函数的返回值
实践:分析一段Shell脚本
1 #!/bin/bash
2 #
3
4 function prepare_check() {
5 isRoot=`id -u -n | grep root | wc -l`
6 if [ "x$isRoot" != "x1" ]; then
7 echo -e "[\033[31m ERROR \033[0m] Please use root to execute the installation script (请用 root 用户执行安装脚本)"
8 exit 1
9 fi
10 processor=`cat /proc/cpuinfo| grep "processor"| wc -l`
11 if [ $processor -lt 2 ]; then
12 echo -e "[\033[31m ERROR \033[0m] The CPU is less than 2 cores (CPU 小于 2核,JumpServer 所在机器的 CPU 需要至少 2核)"
13 exit 1
14 fi
15 memTotal=`cat /proc/meminfo | grep MemTotal | awk '{print $2}'`
16 if [ $memTotal -lt 3750000 ]; then
17 echo -e "[\033[31m ERROR \033[0m] Memory less than 4G (内存小于 4G,JumpServer 所在机器的内存需要至少 4G)"
18 exit 1
19 fi
20 }
21
22 function install_soft() {
23 if command -v dnf > /dev/null; then
24 if [ "$1" == "python" ]; then
25 dnf -q -y install python2
26 ln -s /usr/bin/python2 /usr/bin/python
27 else
28 dnf -q -y install $1
29 fi
30 elif command -v yum > /dev/null; then
31 yum -q -y install $1
32 elif command -v apt > /dev/null; then
33 apt-get -qqy install $1
34 elif command -v zypper > /dev/null; then
35 zypper -q -n install $1
36 elif command -v apk > /dev/null; then
37 apk add -q $1
38 else
39 echo -e "[\033[31m ERROR \033[0m] Please install it first (请先安装) $1 "
40 exit 1
41 fi
42 }
43
44 function prepare_install() {
45 for i in curl wget zip python; do
46 command -v $i &>/dev/null || install_soft $i
47 done
48 }
49
50 function get_installer() {
51 echo "download install script to /opt/jumpserver-installe (开始下载安装脚本到 /opt/jumpserver-installe)"
52 Version=$(curl -s 'https://api.github.com/repos/jumpserver/installer/releases/latest' | grep "tag_name" | head -n 1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
53 if [ ! "$Version" ]; then
54 echo -e "[\033[31m ERROR \033[0m] Network Failed (请检查网络是否正常或尝试重新执行脚本)"
55 fi
56 cd /opt
57 if [ ! -d "/opt/jumpserver-installer-$Version" ]; then
58 wget -qO jumpserver-installer-$Version.tar.gz https://github.com/jumpserver/installer/releases/download/$Version/jumpserver-installer-$Version.tar.gz || {
59 rm -rf /opt/jumpserver-installer-$Version.tar.gz
60 echo -e "[\033[31m ERROR \033[0m] Failed to download jumpserver-installer (下载 jumpserver-installer 失败, 请检查网络是否正常或尝试重新执行脚本)"
61 exit 1
62 }
63 tar -xf /opt/jumpserver-installer-$Version.tar.gz -C /opt || {
64 rm -rf /opt/jumpserver-installer-$Version
65 echo -e "[\033[31m ERROR \033[0m] Failed to unzip jumpserver-installe (解压 jumpserver-installer 失败, 请检查网络是否正常或尝试重新执行脚本)"
66 exit 1
67 }
68 rm -rf /opt/jumpserver-installer-$Version.tar.gz
69 fi
70 }
71
72 function config_installer() {
73 cd /opt/jumpserver-installer-$Version
74 JMS_Version=$(curl -s 'https://api.github.com/repos/jumpserver/jumpserver/releases/latest' | grep "tag_name" | head -n 1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
75 if [ ! "$JMS_Version" ]; then
76 echo -e "[\033[31m ERROR \033[0m] Network Failed (请检查网络是否正常或尝试重新执行脚本)"
77 exit 1
78 fi
79 sed -i "s/VERSION=.*/VERSION=$JMS_Version/g" /opt/jumpserver-installer-$Version/static.env
80 ./jmsctl.sh install
81 }
82
83 function main(){
84 prepare_check
85 prepare_install
86 get_installer
87 config_installer
88 }
89
90 main
分析
#不要被那么多代码量给吓到了,我们慢慢来分析
#先了解整个shell的框架如下,
"定义的函数不会直接运行,必须通过函数名去调用才会执行"
prepare_check() {
#定义prepare_check函数
}
install_soft() {
#定义install_soft函数
}
prepare_install() {
#定义prepare_install函数
}
get_installer() {
#定义get_installer函数
}
config_installer() {
#定义config_installer函数
}
main() {
#定义主函数
}
main #执行主函数
#我们了解到这段shell脚本有6个函数
#shell一开始运行并不会直接执行某个函数,只是定义了一个函数告诉系统有这么个名字为***的函数
#使用函数名进行调用,才会运行函数体里面的语句!
#我们从大概的结构看,最后一行对main主函数进行了调用,也就是运行main主函数,我们来分析以下主函数里面做了什么?
主函数
function main(){
prepare_check #第一步:调用prepare_check函数
prepare_install #第二步:调用prepare_install函数
get_installer #第三步:调用get_installer函数
config_installer #第四步:调用config_installer函数
}
# 主函数main函数体内对4个自定义函数进行了调用,当调用prepare_check函数则程序会跳转到prepare_check函数体内执行此函数体内的代码
# 接下来我们分析prepare_check函数
prepare_check函数
function prepare_check() {
isRoot=`id -u -n | grep root | wc -l`
#执行命令id -u -n | grep root | wc -l并将返回值赋值给isRoot变量
#判断当前用户是否为root用户并对输出的结果计数
#如果是root用户则为1否则为0
if [ "x$isRoot" != "x1" ]; then #条件判断,这里的$isRoot为调用变量,如果x$isRoot不等于"x1"
#如果满足上面的条件则执行下面两条语句
#输出:请用 root 用户执行安装脚本的提示
#-e选项是激活转义字符 “\”表示转义 [\033[31m ERROR \033[0m] 表示ERROR用红色显示
echo -e "[\033[31m ERROR \033[0m] Please use root to execute the installation script (请用 root 用户执行安装脚本)"
#exit为退出
exit 1
fi
processor=`cat /proc/cpuinfo| grep "processor"| wc -l`
#执行命令cat /proc/cpuinfo | grep "processor" | wc -l 对/proc/cpuinfo文件的processor的字段进行计数并将结果赋值给processor变量
if [ $processor -lt 2 ]; then #条件判断,如果processor变量的值小于2
#输出:CPU 小于 2核,JumpServer 所在机器的 CPU 需要至少 2核
echo -e "[\033[31m ERROR \033[0m] The CPU is less than 2 cores (CPU 小于 2核,JumpServer 所在机器的 CPU 需要至少 2核)"
#退出shell
exit 1
fi
memTotal=`cat /proc/meminfo | grep MemTotal | awk '{print $2}'` #输出/proc/meminfo文件的MemTotal字段的第二列的结果赋值给memTotal变量
if [ $memTotal -lt 3750000 ]; then #判断memTotal变量的值是否小于3750000
#输出:内存小于 4G,JumpServer 所在机器的内存需要至少 4G
echo -e "[\033[31m ERROR \033[0m] Memory less than 4G (内存小于 4G,JumpServer 所在机器的内存需要至少 4G)"
#退出shell
exit 1
fi
}
#prepare_check函数主要用来判断主机的CPU、内存、用户是否都满足条件,如果不满足则退出shell脚本
#如果满足我们则执行main函数的第二条语句
#看下面
主函数
function main(){
prepare_check #这步已经执行完毕,主机各项配置都符合条件,接下来执行下面那条语句;如果第一个函数其中一项不满足条件,整个shell进行退出,不会再执行下面的语句了。
prepare_install #第二步:调用prepare_install函数
get_installer #第三步:调用get_installer函数
config_installer #第四步:调用config_installer函数
}
#下面进入prepare_install函数
prepare_install函数
function prepare_install() {
for i in curl wget zip python; do
#使用for循环进行迭代,for循环共会执行4次,每次的i变量的参数为curl、wget、zip、python
command -v $i &>/dev/null || install_soft $i
#使用command -v 命令判断i变量中的参数(也就是判断系统有没有这个命令),如果有,则开始下一轮循环,如果没有则调用install_soft函数并传递变量i的值,并进行相应命令的安装
done
}
#本函数用来判断Linux系统中是否存在curl、wget、zip、python这四条命令,如果都有,则本函数执行完毕!如果没有则将没有的命令通过变量i传递至install_soft函数
#接下来我们看install_soft函数
install_soft函数
function install_soft() {
if command -v dnf > /dev/null; then #判断系统是否有dnf命令
if [ "$1" == "python" ]; then #判断$1为 调用函数时传递进来的参数 也就是没有前面没有安装的命令 判断是否为python
dnf -q -y install python2 #安装python2
ln -s /usr/bin/python2 /usr/bin/python #对python2命令进行软链接
else
dnf -q -y install $1 #如果不等于python则安装$1 也就是传递进来的参数(命令)
fi
elif command -v yum > /dev/null; then #判断系统是否有yum命令
yum -q -y install $1 #安装$1变量里的命令
elif command -v apt > /dev/null; then #判断系统是否有apt命令
apt-get -qqy install $1 #安装$1变量里的命令
elif command -v zypper > /dev/null; then #判断系统是否有zypper命令
zypper -q -n install $1 #安装$1变量里的命令
elif command -v apk > /dev/null; then #判断系统是否有apk命令
apk add -q $1 #安装$1变量里的命令
else
echo -e "[\033[31m ERROR \033[0m] Please install it first (请先安装) $1 " #如果以上方法都无法进行安装,则输出:...请安装**
#退出shell
exit 1
fi
}
#回到prepare_install函数
prepare_install函数
function prepare_install() {
for i in curl wget zip python; do
command -v $i &>/dev/null || install_soft $i
done
}
#通过prepare_install函数和install_soft的判断和安装
#我们可以确定系统已经有curl wget zip python等4条命令了,如果正常执行完install_soft函数体里的命令(不正常情况shell已退出),则回到main主函数
主函数
function main(){
prepare_check #这步已经执行完毕,主机各项配置都符合条件,接下来执行下面那条语句;如果第一个函数其中一项不满足条件,整个shell进行退出,不会再执行下面的语句了。
prepare_install #这部已经执行完毕,主机必要的命令已存在
get_installer #第三步:调用get_installer函数
config_installer #第四步:调用config_installer函数
}
#下面进入get_isntaller函数
get_installer函数
function get_installer() {
echo "download install script to /opt/jumpserver-installe (开始下载安装脚本到 /opt/jumpserver-installe)"
#输出:开始下载安装脚本...
Version=$(curl -s 'https://api.github.com/repos/jumpserver/installer/releases/latest' | grep "tag_name" | head -n 1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
#对链接的信息进行筛选,找到"tag-name"字符的第一行,并对接下来的结果筛选,并将结果赋值给Version变量
if [ ! "$Version" ]; then # 取反
echo -e "[\033[31m ERROR \033[0m] Network Failed (请检查网络是否正常或尝试重新执行脚本)"
fi
cd /opt #进入/opt目录
if [ ! -d "/opt/jumpserver-installer-$Version" ]; then #判断这个目录是否存在,并取反
#如果不存在,则开始下载相应的文件,如果下载不成功,删除下载的文件,并提示检查网络是否正常
wget -qO jumpserver-installer-$Version.tar.gz https://github.com/jumpserver/installer/releases/download/$Version/jumpserver-installer-$Version.tar.gz || {
rm -rf /opt/jumpserver-installer-$Version.tar.gz
echo -e "[\033[31m ERROR \033[0m] Failed to download jumpserver-installer (下载 jumpserver-installer 失败, 请检查>网络是否正常或尝试重新执行脚本)"
exit 1
}
# 下载成功后对文件进行解压缩 || 前者不成功则进行删除相应的目录并提示:网络问题或重新执行脚本并退出
tar -xf /opt/jumpserver-installer-$Version.tar.gz -C /opt || {
rm -rf /opt/jumpserver-installer-$Version
echo -e "[\033[31m ERROR \033[0m] Failed to unzip jumpserver-installe (解压 jumpserver-installer 失败, 请检查网络>是否正常或尝试重新执行脚本)"
exit 1
}
# 如果成功解压后,删除下载的压缩包
rm -rf /opt/jumpserver-installer-$Version.tar.gz
fi
}
#成功执行完毕返回main主函数
主函数
function main(){
prepare_check #这步已经执行完毕,主机各项配置都符合条件,接下来执行下面那条语句;如果第一个函数其中一项不满足条件,整个shell进行退出,不会再执行下面的语句了。
prepare_install #这部已经执行完毕,主机必要的命令已存在
get_installer #这部已经执行完毕,相应的文件已下载并解压
config_installer #第四步:调用config_installer函数
}
#下面进入config_installer函数
config_installer函数
function config_installer() {
cd /opt/jumpserver-installer-$Version
# 进入相应的目录
JMS_Version=$(curl -s 'https://api.github.com/repos/jumpserver/jumpserver/releases/latest' | grep "tag_name" | head -n 1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g')
#将链接的信息进行筛选并赋值给JMS_Version变量
if [ ! "$JMS_Version" ]; then #取反
#如果为假 则提示:检查网络或重新执行脚本,并退出
echo -e "[\033[31m ERROR \033[0m] Network Failed (请检查网络是否正常或尝试重新执行脚本)"
exit 1
fi
sed -i "s/VERSION=.*/VERSION=$JMS_Version/g" /opt/jumpserver-installer-$Version/static.env
#在/opt/jumpserver-installer-$Version/static.env文件中插入s/VERSION=.*/VERSION=$JMS_Version/g参数
./jmsctl.sh install
#运行脚本
}
#config_installer函数执行完毕,返回主函数main
主函数
function main(){
prepare_check #这步已经执行完毕,主机各项配置都符合条件,接下来执行下面那条语句;如果第一个函数其中一项不满足条件,整个shell进行退出,不会再执行下面的语句了。
prepare_install #这部已经执行完毕,主机必要的命令已存在
get_installer #这部已经执行完毕,相应的文件已下载并解压
config_installer #这部已经执行完毕,已配置完毕相应的配置并运行jumpserver
}
#---------------------- 至此shell分析结束,如果有不到位的请留言提出qwq或私信我--------------------
#
# 除了某些命令可能不是很了解,其实看完前面的基础和掌握Linux基础命令,对上面的shell也能大致的进行分析了
#
# 接下来就是多多练习了~
#