Shell 脚本语言
1.Shell 编程概述
Shell 是一种命令行解释器,它为用户提供了与操作系统内核进行交互的接口。在 Unix、Linux 和类 Unix 系统(包括 macOS)中,Shell 是用户与计算机之间的重要沟通桥梁。用户可以通过 Shell 输入命令来执行各种操作,比如文件管理、程序运行、进程控制等。
1.1 Shell 名称解释
-
Kernel
- Linux 内核主要是为了和硬件打交道
-
Shell
- 命令解释器 (command interpreter)
- Shell 是一个用C语言编写的程序, 它是用户使用Linux的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。
- Shell 是指一种应用程序, 这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。
-
Shell 两大主流:
- sh:
- Bourne Shell (sh),Solaris,hpux 默认Shell
- Bourne again shell (bash),Linux 默认shell
- csh:
- C shell (csh)
- tc shell(tcsh)
- sh:
-
#! 声明
-
告诉系统其后路径所指定的程序即是解释此脚本文件的Shell程序
-
#! /bin/bash
echo “Hello World!”
-
1.2 Shell 脚本的执行
- 输入脚本的绝对路径或相对路径
# 查询文件可执行权限
[root@linux-1 shell]# ll
total 8
-rw-rw-r-- 1 root root 35 Jul 30 15:47 hello.sh
-rw-r--r-- 1 root root 32 Jul 30 16:02 hi.sh
# chmod 修改文件可执行权限
[root@linux-1 shell]# chmod ug+x hello.sh
[root@linux-1 shell]# ll
total 8
-rwxrwxr-- 1 root root 35 Jul 30 15:47 hello.sh
-rw-r--r-- 1 root root 32 Jul 30 16:02 hi.sh
# 可以通过相对路径或者绝对路径执行脚本文件,执行的文件必须是可执行文件,
[root@linux-1 shell]# ./hello.sh
Hello World!
[root@linux-1 shell]# /root/shell/hello.sh
Hello World!
- bash 或 sh 命令
# 脚本文件没有可执行权限时,通过路径是无法执行的
[root@linux-1 shell]# ./hi.sh
-bash: ./hi.sh: Permission denied
# 可以通过 sh,bash 命令执行
[root@linux-1 shell]# sh hi.sh
Hi World!
[root@linux-1 shell]# bash hi.sh
Hi World!
- source 命令
# source 命令执行
[root@linux-1 shell]# source hi.sh
Hi World!
- 三种方式区别如下
# 声明变量,在hello.sh脚本中打印,路径执行脚本和sh 命令执行脚本不会打印变量
# 使用source命令执行脚本则会打印变量
[root@linux-1 shell]# uname=admin
[root@linux-1 shell]# echo $uname
admin
[root@linux-1 shell]# vim hello.sh
[root@linux-1 shell]# cat hello.sh
#! /bin/bash
echo "Hello World!"
echo $uname
[root@linux-1 shell]# ./hello.sh
Hello World!
[root@linux-1 shell]# sh hello.sh
Hello World!
[root@linux-1 shell]# source hello.sh
Hello World!
admin
- 修改脚本 hello.sh
[root@linux-1 shell]# cat hello.sh
#! /bin/bash
echo "Hello World!"
echo $uname
ping www.baidu.com
- 路径执行脚本,打印当前进程
# 执行脚本
[root@linux-1 shell]# ./hello.sh
# 打印进程
[root@linux-1 shell]# ps -ef

通过bash 9730的进程创建了一个子进程9772 执行了脚本,但未打印临时变量值,由于临时变量uname声明在9730进程中,两个进程之间无法通信,所以通过路径的方式执行脚本无法打印出临时变量的值
- sh 命令执行脚本
# 执行脚本
[root@linux-1 shell]# sh hello.sh
# 打印进程
[root@linux-1 shell]# ps -ef

通过bash 9730的进程创建了一个子进程9792 执行了脚本,和路径执行脚本类似,进程之间不能通信(一般情况),所以不能打印临时变量的值
- source命令执行脚本
# 执行脚本
[root@linux-1 shell]# source hello.sh
# 打印进程
[root@linux-1 shell]# ps -ef

通过bash 9730的进程直接执行了脚本,没有创建新的进程,而临时变量uname在9730进程中声明,可以直接拿到值,打印出临时变量的值
Tip
第一种和第二种会新开一个bash,不同的bash中的变量是无法共享的,source 是在同一个shell里面执行的
- export:可以将当前进程的变量传递给子进程去使用
- 将来配置profile的时候,所有的变量前必须加export
2.Shell 基础入门
2.1 Shell变量
-
定义变量时,变量名不加美元符号
- 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头
- 中间不能有空格,可以使用下划线 (_) 。
- 不能使用标点符号
- 不能使用bash里的关键字 (可以使用help命令查看保留关键字)
-
变量的类型
- 局部变量
- 局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
- 环境变量
- 所有程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。
- Shell变量
- shell变量是由shell程序设置的特殊变量,shell变量有一部分是环境变量,有一部分是局部变量。
- 局部变量
# 变量的声明
name="zhangsan"
# 变量的调用
echo $name
echo ${name}
# 只读变量,也不能删除
url="https://www.google.com"
readonly url
url="xx"
# 执行脚本异常
./hello.sh: line 11: url: readonly variable
# 删除变量
unset name
2.2 Shell的字符串
-
字符串是shell编程中最常用最有用的数据类型,字符串可以用单引号,也可以用双引号,也可以不用引号。
-
单引号
- 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
- 单引号字符串中不能出现单独一个的单引号,但可以成对出现,作为字符串拼接使用
-
双引号
- 双引号里可以有变量
- 双引号里可以出现转义字符
# 声明字符串
[root@linux-1 shell]# str1="hello world 1"
[root@linux-1 shell]# str2='hello world 2'
# 字符串拼接--双引号,会转义$引用的变量
[root@linux-1 shell]# echo $name
wang wu
[root@linux-1 shell]# str1="hello,$name"
[root@linux-1 shell]# str2="hello,"$name""
[root@linux-1 shell]# echo $str1
hello,wang wu
[root@linux-1 shell]# echo $str2
hello,wang wu
# 字符串拼接--单引号
[root@linux-1 shell]# passwd='123456'
# 使用了单引号引用的变量会进行转义,未使用单引号引用的变量不会转义
[root@linux-1 shell]# passwd1='hello,'$passwd''
[root@linux-1 shell]# passwd2='hello,$passwd'
[root@linux-1 shell]# echo $passwd1
hello,123456
[root@linux-1 shell]# echo $passwd2
hello,$passwd
# 字符串的长度
[root@linux-1 shell]# email="12345@qq.com"
# 使用# 获取长度
[root@linux-1 shell]# echo ${#email}
12
# 截取 变量:起始索引:长度
[root@linux-1 shell]# echo ${email:1:4}
2345
2.3 Shell 数组
- bash 支持一维数组 (不支持多维数组),并且没有限定数组的大小。
- 数组元素的下标由0开始编号,获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于0。
# 定义数组 括号表示数组,数组元素用“空格”符合分割开
数组名=(值1 值2 ... 值n)
[root@linux-1 shell]# values=("足球" "篮球" "乒乓球")
# 读取数组 ${数组名[下标]}
[root@linux-1 shell]# echo ${values[0]}
足球
# 使用@/*符合可以获取数组中的所有元素
[root@linux-1 shell]# echo ${values[@]}
足球 篮球 乒乓球
[root@linux-1 shell]# echo ${values[*]}
足球 篮球 乒乓球
# 获取数组长度
[root@linux-1 shell]# echo ${#values[@]}
3
[root@linux-1 shell]# echo ${#values[*]}
3
2.4 Shell 的注释
- 以#开头的行就是注释,会被解释器忽略
- 通过每一行加一个# 号设置多行注释
#----------------------
# 这是一个注释
# author:
# site:
##### 服务器配置-start #####
#
#
#
#
#
##### 服务器配置-end #####
# 特殊的多行注释
:<<EOF
注释内容...
注释内容...
注释内容...
EOF
:<<!
注释内容...
注释内容...
注释内容...
!
3.Sell 高级进阶
3.1 Shell 运算符
-
运算符的分类
a=10 b=20-
算术运算符
-
运算符 说明 举例 + 加法 expr $a + $b结果为30- 减法 expr $a - $b结果为-10* 乘法 expr $a \* $b结果为 200/ 除法 expr $b / $a结果为 2% 取余 expr $b % $a结果为0= 赋值 a=$b 将变量b 的值赋值给a == 相等。用于比较两个数字,相同则返回true [ $a == $b ] 返回 false != 不相等。用于比较两个数字,不相同则返回true [ $a != $b ] 返回 true -
关系运算符
-
运算符 说明 举例 -eq 检测两个数是否相等,相等返回true [ $a -eq $b] 返回 false -ne 检测两个数是否不相等,不相等返回true [ $a -ne $b] 返回 true -gt 检测左边的数是否大于右边的,如果是,则返回true [ $a -gt $b] 返回 false -lt 检测左边的数是否小于右边的,如果是,则返回true [ $a -lt $b] 返回 true -ge 检测左边的数是否大于等于右边的,如果是,则返回true [ $a -ge $b] 返回 false -le 检测左边的数是否小于等于右边的,如果是,则返回true [ $a -le $b] 返回 true -
布尔运算符
-
运算符 说明 举例 ! 非运算,表达式为true,则返回false,否则返回true [!false] 返回 true -o 或运算,有一个表达式为true,则返回false [$a -lt 20 -o $b -gt 100] 返回 true -a 与运算,两个表达式都为true,才返回true [$a -lt 20 -a $b -gt 100] 返回 false -
字符串运算符
-
运算符 说明 举例 && 逻辑的AND [[$a -lt 100 && $b -gt 100]] 返回 false || 逻辑的OR [[$a -lt 100 || $b -gt 100 ]] 返回 true -
文件测试运算符
-
运算符 说明 举例 = 检测两个字符串是否相等,相等返回true [ $a = $b ] 返回 false != 检测两个字符串是否相等,不相等返回true [ $a != $b ] 返回 true -z 检测字符串长度是否为0,为0返回true [ -z $a ] 返回 false -n 检测字符串长度是否不为0,不为0 返回 true [ -n “$a” ] 返回 true $ 检测字符串是否为空,不为空返回true [ $a ] 返回 true
-
3.1.1 算术运算符
- expr 是一款表达式计算工具,使用它能完成表达式的求值操作。
#! /bin/bash
a=10
b=20
val=`expr $a + $b`
echo "a + b : $val"
val=`expr $a - $b`
echo "a - b : $val"
val=`expr $a \* $b`
echo "a * b : $val"
val=`expr $b / $a`
echo "b / a : $val"
val=`expr $a % $b`
echo "b % a : $val"
if [ $a == $b ]
then
echo "a == b"
fi
if [ $a != $b ]
then
echo "a != b"
fi
3.1.2 关系运算符
- 关系运算符只支持数字,不支持字符串,除非字符串的值是数字
#! /bin/bash
a=10
b=20
if [ $a -eq $b ]
then
echo "$a -eq $b : a == b"
else
echo "$a -eq $b : a != b"
fi
if [ $a -ne $b ]
then
echo "$a -ne $b : a != b"
else
echo "$a -ne $b : a == b"
fi
if [ $a -gt $b ]
then
echo "$a -gt $b : a > b"
else
echo "$a -gt $b : a <= b"
fi
if [ $a -lt $b ]
then
echo "$a -lt $b : a < b"
else
echo "$a -lt $b : a >= b"
fi
if [ $a -ge $b ]
then
echo "$a -ge $b : a >= b"
else
echo "$a -ge $b : a < b"
fi
if [ $a -le $b ]
then
echo "$a -le $b : a <= b"
else
echo "$a -le $b : a > b"
fi
3.1.3 布尔运算符
#! /bin/bash
a=10
b=20
if [ $a != $b ]
then
echo "$a != $b : a 不等于 b"
else
echo "$a == $b : a 等于 b"
fi
if [ $a -lt 100 -a $b -gt 15 ]
then
echo "$a < 100 and $b > 15 : return true"
else
echo "$a < 100 and $b > 15 : return false"
fi
if [ $a -lt 100 -o $b -gt 15 ]
then
echo "$a < 100 or $b > 15 : return true"
else
echo "$a < 100 or $b > 15 : return false"
fi
3.1.4 逻辑运算符
#! /bin/bash
a=10
b=20
if [[ $a -lt 100 && $b -gt 100 ]]
then
echo "返回 true"
else
echo "返回 false"
fi
if [[ $a -lt 100 || $b -gt 100 ]]
then
echo "返回 true"
else
echo "返回 false"
fi
3.1.5 字符串运算符
#! /bin/bash
a="abc"
b="efg"
if [ $a = $b ]
then
echo "$a = $b : a == b"
else
echo "$a = $b : a != b"
fi
if [ $a != $b ]
then
echo "$a != $b : a != b"
else
echo "$a != $b : a == b"
fi
if [ -z $a ]
then
echo "-z $a : 字符串长度0"
else
echo "-z $a : 字符串长度不为0"
fi
if [ -n $a ]
then
echo "-n $a : 字符串长度不为0"
else
echo "-n $a : 字符串长度为0"
fi
if [ $a ]
then
echo "$a : length not 0"
else
echo "$a : length 0"
fi
3.1.6 文件测试运算符
#! /bin/bash
file="/root/shell/hi.sh"
if [ -r $file]
then
echo "文件可读"
else
echo "文件不可读"
fi
if [ -w $file]
then
echo "文件可写"
else
echo "文件不可写"
fi
if [ -x $file]
then
echo "文件可执行"
else
echo "文件不可执行"
chmod ug+x $file
echo "修改文件执行权限"
fi
if [ -f $file]
then
echo "文件为普通文件"
else
echo "文件为特殊文件"
fi
if [ -d $file]
then
echo "文件是个目录"
else
echo "文件不是个目录"
fi
if [ -s $file]
then
echo "文件不为空"
else
echo "文件为空"
fi
if [ -e $file]
then
echo "文件存在"
else
echo "文件不存在"
fi
3.2 echo 打印数据
- shell 的echo 指令用于字符串输出
#! /bin/bash
## 显示普通字符串
echo "Hello World!"
## 显示转义字符
echo "\"Hello World\""
## 显示变量
name="zhangsan"
echo "$name Hello World"
## 显示换行
echo -e "OK! \n"
echo "Hello World"
## 显示不换行
echo -e "OK ! \c"
echo "Hello World"
## 显示结果定向至指定文件
echo "Hello World" > echo.log
## 原样输出字符串
echo '$name\"'
## 显示命令执行结果
echo `date`
3.3 Shell 流程控制
3.3.1 if
#! /bin/bash
a=10
b=20
if [ $a == $b ]
then
echo "a 等于 b"
elif [ $a -gt $b ]
then
echo "a 大于 b"
else
echo "a 小于 b"
fi
3.3.2 case
- shell case 语句为多选择语句,可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令
#! /bin/bash
key="redis_key"
case $key in
"redis_key1")
echo "关键值"
;;
*) # * 和 default类似
echo "没有值"
;; # ;; 和 break 类似
esac # 结束标识
3.3.3 for
- 当变量值在列表里,for循环即执行一次所有命令,使用变量名获取列表中的当前取值。
- 命令可为任何有效的shell命令和语句,in列表可以包含替换、字符串和文件名
- in列表是可选的,如果不用它,for循环使用命令行的位置参数。
#! /bin/bash
for item in "葡萄" "西瓜" "荔枝"
do
echo "当前水果 $item"
done
3.3.4 while 循环
- while 循环用于不断执行一系列命令,也用于从输入文件中读取数据;命令通常为从测试条件。
#! /bin/bash
# bash let 命令用于执行一个或多个表达式,变量计算中不需要加$表示变量
# 方式一
i=1
while(( $i < 5))
do
echo $i
let "i++"
done
#方式二
i=1
while(( $i < 5))
do
echo $i
i=$(($i+1))
done
3.3.5 break
- break 命令允许跳出所有循环 (终止执行后面的所有循环)
#! /bin/bash
while :
do
echo -n "输入 1 到 5 之间的数字:"
read num
case $num in
1|2|3|4|5) echo "输入的数字为 $num!"
;;
*)
echo "输入的数字不在 1-5 之间"
break
;;
esac
done
3.3.6 continue
- cointinue 命令不会跳出所有循环,仅仅跳出当前循环
#! /bin/bash
while :
do
echo -n "输入 1 到 5 之间的数字:"
read num
case $num in
1|2|3|4|5) echo "输入的数字 $num"
;;
*) echo "你输入的数字不是 1 到 5 之间的!"
continue
echo "游戏结束"
;;
esac
done
3.4 Shell 函数
- linux shell 可以用户定义函数,然后在shell 脚本中可以随便调用。
- 可以带function fun() 定义,也可以直接 fun() 定义,不带任何参数。
- 参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。return 后跟数值 n(0-255)
#! /bin/sh
## 第一个函数-----------------------
demoFun(){
echo "这是我的第一个 shell 函数!"
}
echo "---------函数开始执行---------"
demoFun
echo "---------函数执行完毕---------"
## 函数返回值-----------------------
function funWithReturn()
{
echo "这个函数会对输入的两个数字进行相加运算..."
echo "输入第一个数字:"
read num1
echo "输入第二个数字:"
read num2
echo "两个数字分别为 $num1 和 $num2 !"
return $(($num1+$num2))
}
funWithReturn
## 函数返回值在调用函数后通过 $? 或取
echo "fun结果为:$?"
## 函数参数-------------------------
function funWithParam(){
echo "第一个参数为 $1 !"
echo "第二个参数为 $2 !"
echo "第十个参数为 $10 !" # 超过10需要加上{}
echo "第十个参数为${10} !"
echo "参数总数为 $# !"
echo "作为一个字符串输出所有参数 $* !"
}
funWithParam 1 2 3 4 5 6 7 8 9 0
4.系统任务设置
4.1 系统启动流程
-
启动计算机的硬件(BIOS)
- 读取时间
- 选择对应的启动模式(USB HDD EFI)
-
如果是Linux 系统,回去找/boot/目录引导系统启动
-
计算机系统开始启动,读取初始化配置文件
-
vim/etc/inittab
-
启动时控制着计算机的运行级别 runlevel
-
0 halt(关机) 1 Single user mode(单用户模式) 2 Multiuser,without NFS (多用户模式,但是无网络状态)FS --> FileSystem 3 Full multiuser mode(多用户完整版模式) 4 unused(保留模式) 5 X11(用户界面模式) 6 reboot(重启模式) -
id:3:initdefault: 默认runlevel为3
-
以runlevel=3 开始启动对应的服务和组件
-
-
开始默认引导公共的组件或者服务
- vim /etc/rc.d/rc.sysinit
-
开始加载对应runlevel的服务
- vim /etc/rc3.d/
4.2 系统服务
- 使用 chkconfig 命令查看当前虚拟机的服务
- 通过查看可以得知不同的级别对应到每一个服务确定本次开机自动启动
- 开机结束后,我们需要使用 service (Centos6) Systemctl(Centos7) 命令控制服务的开启或者关闭
4.3 开机自启动服务
-
rc.local
- 首先创建脚本存放的文件夹
- mkdir -p /usr/local/scrips
- 在文件夹中创建脚本文件
- vim hello.sh
- 给予执行权限
- 去 /etc/rc.d/rc.local 文件中添加脚本的绝对路径
- 给予 rc.local 执行权限
- 修改系统时间
- date -s ‘21-21-21’
- 重启虚拟机
- reboot
- 首先创建脚本存放的文件夹
-
chkconfig
-
创建开机自启动脚本文件
-
vim updateDate.sh
#! /bin/bash # chkconfig: 35 66 88 #35 表示 rc3,rc5 66表示启动 88关闭 # description: auto_run # 开机自启动同步时间 yum info ntp && ntpdate cn.ntp.org.cn
-
修改执行权限
- chmod ug+x updateDate.sh
-
拷贝到 /etc/init.d/ 目录下
- cp updateDate.sh /etc/init.d/
-
添加到服务
- chkconfig --add /etc/init.d/updateDate.sh
-
修改系统时间
- date -s ‘21-21-21’
-
重启服务器
- reboot
-
2万+

被折叠的 条评论
为什么被折叠?



