shell学习

shell学习

1. shell简介

1.1什么是shell

在linuxi系统与用户之间的解释器程序。默认为/bin/bash。

负责向内核翻译传达用户/程序指令。

位于系统内核与用户之间。

1.2 shell使用方式

交互式:命令行,人工,逐条,效率低

非交互式:脚本,批量,后台,高效率 脚本一般使用非交互式指令

1.3 常见shell种类

[[root@svr7 ~]# cat /etc/shells 
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
/bin/tcsh
/bin/csh

1.4 bash基本特性

1.命令历史:history
    环境变量:
    HISTSIZE:命令历史记录的条数
    HISTFILE:~/.bash-history
    HISTFILESIZE:命令历史文件记录历史的条数
    控制命令历史的记录方式:
    环境变量:HISTCONTROL
    ignoredups:忽略重估的命令(连续且相同方为重复)
    ignorespace:忽略所有以空白开头的命令
    ignoreboth: ignoredups,ignorespace
2.命令补全:tab键
3.路径补全
4.命令行展开
        ~:展开为用户的主目录
        ~USERNAME:展开为指定用户的主目录
        {}:可承载一个以逗号分隔的列表,并将其展开为多个路径
                /tmp/{a,b}  =  /tmp/a ,  /tmp/b
                /tmp/{a,b}/hi  = /tmp/a/hi  ,  /tmp/b/hi
5.命令执行结果状态
    bash使用特殊变量$?保存最近一条命令的执行状态结果
    echo    $?:显示上一条命令执行的结果,返回0表示命令执行成功,返回1-255表示命令执行失败
6.别名:alias
7.glob(通配符)
        bash中用于实现文件名通配,
        通配符:
                *:任意长度的任意字符
            ?:任意单个字符
             []:匹配指定范围内的任意单个字符
                     [0-9]:匹配数字
                     [a-z]:匹配字母,不区分大小写
                     [A-Z]:匹配大写字母
             [^]:匹配指定范围外的任意单个字符
             专用字符集合:
                     [:digit:]:任意数字,相当于0-9,若匹配数字,则[[:digit:]]
                     [:lower:]:任意小写字母
                     [:upper:]:任意大写字母
                     [:alpha:]:任意大小写字母
                     [:alnum:]:任意数字或字母
                     [:space:]:空格
                     [:punct:]:标点符号
8.快捷键
        ctrl + l :清屏,相当于clear
        ctrl + a:调到命令开始处
        ctrl + e:跳到命令结尾处
        ctrl + u:删除命令行首到光标所在处的内容
        ctrl + k:删除光标至行尾的内容
9.> 重定向标准输出:命令正确的输出
  2> 重定向错误输出:命令不正确输出
  &> 重定向所有输出:不论什么类型,全部输出
  [root@node-0001 shell]# ls yum.sh a
	ls: 无法访问'a': 没有那个文件或目录    错误输出
	yum.sh							   标准输出
	mount /dev/cdrom /mydvd &>/dev/null

2. 什么事shell脚本?

提前写好的可执行程序,完成特定任务的文件。

顺序、批量化处理

是一种解释型程序。与Windows 的.bat文件相似。

2.1 shell 编程有哪些注意事项

​ shell 命名:Shell脚本名称命名一般为英文、大写、小写,后缀以.sh 结尾
​ 不能使用特殊符号、空格
​ 见闻之意,名称要写的一眼可以看出功能
​ shell 编程 首行需要 #!/bin/bash 开头
​ shell 脚本 变量 不能以 数字、特殊符号开头,可以使用下划线—,但不能 用破折号

​ shell 脚本运行前需要修改执行权限,需要以绝对路径执行

​ /opt目录下面随便使用

2.2 shell脚本编写规范

1、声明解释器   		#!/bin/bash
2、编写注释 			 #描述脚本功能、变量作用等信息
3、编写执行指令       #使用非交互式的指令

2.3 shell脚本执行方式

  1. 使用相对或者绝对路径。需要执行权限x
    新开一个bash,用完退出 用户—bash—bash----echo
chmod +x hello.sh
./hello.sh
  1. 使用 bash解释器执行,无需x权限。
    会开启子进程,执行完推出 用户—bash—bash----echo
bash ./hello.sh
  1. 使用source 命令执行脚本,无需x权限。source代表现在默认使用的解释器。
    当前解释器bash亲自执行 用户-----bash-----echo 不开启子进程
source ./test.sh

2.4 shell 注释

1.单行注释:和python注释相同,以#号开头作为单行注释

# 这是一个注释

2.多行注释:如果在开发过程中,遇到大段的代码需要临时注释起来,过一会儿又取消注释,可以将其定义为一个花括号的注释函数,也可以用多行注释

:<<EOF
注释内容...
EOF
# EOF可以换成其他符号
:<<E!
注释内容...
!

把输入重定义到前面的命令,但是 : 是空命令,所以就相当于注释了。
如果注释中有反引号的命令就会报错,反引号部分不会被注释掉,例如var=ls -l就不会被注释掉。

解决注释中反引号的问题

方法1: 注释外面加引号
:<<BLOCK'
....注释内容
'BLOCK
方法2:区块外面加引号
:<<'BLOCK
....注释内容
BLOCK'
方法3:
:<<'
....注释内容
'

BLOCK 为 Here Documents 中的定义符号,名称任意,只要前后匹配就行。

2.5 第一个shell脚本

[root@node-0001 shell]# vim hello.sh
#!/bin/bash
# first shell
echo 'hello world!!!'
[root@node-0001 shell]# chmod a+x hello.sh
[root@node-0001 shell]# ./hello.sh           

2.6 彩色输出

#!/bin/bash
# This is echo color shell
# by author rivers 2021.09-23
# 字体颜色
for i in {31..37}; do
echo -e "\033[$i;40mHello world!\033[0m"          #-e  使用转义字符
done
# 背景颜色
for i in {41..47}; do
echo -e "\033[47;${i}mHello world!\033[0m"   #需要加双引号
done
# 显示方式
for i in {1..8}; do
echo -e "\033[$i;31;40mHello world!\033[0m"
done

3.shell 变量

3.1 变量的定义

​ 常量: 固定不变的值

​ 变量: 使用固定的名字存放可能发生变化的值,可以提高脚本的灵活度、适应力。

​ Shell变量名在定义时,首个字符必须为字母(a-z,A-Z),不能以数字开头,中间不能有空格,可以使用下划线(_),不能使用(-),也不能使用标点符号等。

#有效的变量
NAME
LIBRARY_PATH
_var
var2
#无效的变量
?var=123
user*name=ohuohuo

如果在变量中使用系统命令,需要加上 " `"符号(ESC键下方),如下所示

DATE1=`date`	
DATE2=$(date)           #二者功能相同

3.2 变量的使用

使用变量的时,用英文符号"$"取变量值,对于较长的变量名,建议加上{ }花括号,帮助解释器识别变量的边界,如下

name="test_name"
echo "My name is ${name}and you"
a=10    //创建变量(对变量赋值),名字是a,值是10
a=30    //再次赋值,之前的会被覆盖
echo $a  //调用变量时使用$符号
unset  a  //取消变量的定义
a=    //将变量a赋值为空,效果同上
echo ${a}RMB  //变量名容易与后续字符发生混淆时使用大括号隔开

加上方括号时即所有便后面的语句不留空格,shell也会自动识别边界,默认添加USET一个空格.

已经定义过的变量,可以二次定义并重新被赋值覆盖上一次的变量值.

​ shell中的变量,默认为可读可写类型,如果想要其只可读,需要将其声明为**只读类型变量(**如同const),使用readonly命令

#!/bin/bash
Url="http://www.baidu.com"
readonly Url

删除变量,使用unset,但是unset不能删除只读变量.

#!/bin/sh
name="ohuohuo"
Url="http://www.baidu.com"
readonly Url	# 设置只读变量
unset name		# 可以被删除
unset Url		# 不可被删除
echo $name		# 不被打印出
echo $Url		# 打印出

3.3 变量分类

Shell编程中变量分为三种,分别是系统变量、环境变量和自定义变量

env         #查看环境变量
set          #查看所有变量
3.1 shell系统变量

​ Shell常见的变量之一系统变量,分为位置变量与预定义变量,主要是用于对参数判断和命令返回值判断时使用,系统变量详解如下:

$0 		当前脚本的名称;
$n 		当前脚本的第n个参数,n=1,2,…9;      常用于shell传参
$* 		当前脚本的所有参数(不包括程序本身);
$# 		当前脚本的参数个数(不包括程序本身);
$? 		令或程序执行完后的状态,返回0表示执行成功;
$$ 		程序本身的PID号。
$!		后台运行的最后一个进程的pid
[root@node-0001 shell]# cat \$.sh
#!/bin/bash
echo $0
echo $1
echo $2
echo $3
echo $*
echo $$
echo $#
echo $?
[root@node-0001 shell]# bash \$.sh  a b c d
$.sh
a
b
c
a b c d
17416
4
0
3.2 shell 环境变量

​ Shell常见的变量之二环境变量,主要是在程序运行时需要设置,环境变量详解如下:

PATH  		#命令所示路径,以冒号为分割;
HOME  		#打印用户家目录;
SHELL 		#显示当前Shell类型;
USER  		#打印当前用户名;
ID    		#打印当前用户id信息;
PWD   		#显示当前所在路径;
TERM  		#打印当前终端类型;
HOSTNAME    #显示当前主机名;
PS1         #定义主机命令提示符的;
HISTSIZE    #历史命令大小,可通过 HISTTIMEFORMAT 变量设置命令执行时间;
RANDOM      #随机生成一个 0 至 32767 的整数;
HOSTNAME    #主机名
PS1 #一级提示符    [\u@\h \W]
PS2 #二级提示符    >
3.3 用户自定义变量

​ 用户变量又称为局部变量,主要用在Shell脚本内部或者临时局部使用。

a=rivers 				       #自定义变量A;
Httpd_sort=httpd-2.4.6-97.tar  #自定义变量Httpd_sort;
BACK_DIR=/data/backup/         #自定义变量BACK_DIR;
IPaddress=10.0.0.1			   #自定义变量IPaddress;  
3.4 变量的扩展知识

1)" " 双引号 :用于界定范围

[root@node-0001 shell]# echo "ab cd"

2)’ ’ 单引号: 界定范围,屏蔽特殊符号的功能

[root@node-0001 shell]# echo '$USER'
$USER								  //无法调用变量,$被屏蔽

3)`` 反撇号: 获取命令的执行结果,还可以使用$( )实现相同效果

[root@node-0001 shell]# echo $(date)
[root@node-0001 shell]# echo `date`
  1. read 交互式自定义变量
#!/bin/bash
read -p "please input user name:" a
useradd $a
read -p "please input user passwd:" b
echo "$b" | passwd --stdin "$a"
echo $?
[root@node-0001 shell]# bash user.sh 
please input user name:hehe
please input user passwd:xixi
更改用户 hehe 的密码 。
passwd:所有的身份验证令牌已经成功更新。                            

5)stty -echo 屏蔽显示输出 常用于设置密码时不显示密码

​ stty echo 显示屏幕输出

#!/bin/bash
read -p "please input user name:" a
useradd $a
stty -echo
read -p "please input user passwd:" b
echo "$b" | passwd --stdin "$a"
stty echo 
[root@node-0001 shell]# bash user.sh 
please input user name:hehe
please input user passwd:
更改用户 hehe 的密码 。
passwd:所有的身份验证令牌已经成功更新。  

6)使用export发布全局变量

​ 局部变量 仅仅在当前解释器进程中使用的变量

​ 全局变量 解释器产生的子进程中也可以使用的变量

​ export a 声明全局变量 export -n a 取消全局变量

局部变量
root@node-0001 shell]# a=10
[root@node-0001 shell]# echo $a
10
[root@node-0001 shell]# bash
[root@node-0001 shell]# echo $a

全局变量
[root@node-0001 shell]# b=100
[root@node-0001 shell]# echo $b
100
[root@node-0001 shell]# export b
[root@node-0001 shell]# bash
[root@node-0001 shell]# echo $b
100
3.5 expr 命令

运算并输出结果

expr  1  +  1     //加法,运算符号两边要有空格
expr  2  '*'  2  
expr  2  \*  2   // \是转义符号,可以屏蔽身后一个特殊符号的功能
a=10
b=20
expr $a + $b
expr $a + 100
expr $a + $a
3.6 $[ ]运算

运算,但不输出结果

$[1+1]
echo $[2*2]
echo $[2%2]
a=10
b=20
expr $a + $b
echo $[a+b]
echo $(($a+$b))
3.7 let

不输出,专用于变量的创建,或者变量的自增减

expr或 [ ] 、 []、 [](())方式只进行运算,并不会改变变量的值;

而let命令可以直接对变量值做运算再保存新的值。

用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。

let arg [arg ...]

自加操作:let no++

自减操作:let no–

简写形式 let no+=10,let no-=20,分别等同于 let no=no+10,let no=no-20

# expr 实例
$ s=`expr 2 + 3`
$ echo $s
5
# let 实例
$ let s=(2+3)*4
$ echo $s
20
3.8 bc 浮点数计算

bc 交互式计算

[root@node-0001 shell]# bc
bc 1.07.1
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 
12.34+5.67
18.01

非交互式计算:

​ 将需要运算的表达式通过管道操作交给bc运算。注意,小数位的长度可采用scale=N限制,除此以外也受参与运算的数值的小数位影响。

A.用echo和|法,如:

\# echo "(6+3)*2" |bc
18
\# echo 15/4 |bc
3
\# echo "scale=2;15/4" |bc
3.75
\# echo "3+4;5*2;5^2;18/4" |bc

还有ibase和obase来其它进制的运算。

//将16进制的A7输出为10进制, 注意,英文只能大写
\# echo "ibase=16;A7" |bc
167
//将2进制的11111111转成10进制
\# echo "ibase=2;11111111" |bc
255
//输入为16进制,输出为2进制
\# echo "ibase=16;obase=2;B5-A4" |bc
10001
3.9 条件测试 test

可以赋予脚本智能判断的效果

语法格式 1, test 表达式 2, [ 表达式 ] 注意空格

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mw2zH9Uj-1656903556448)(/root/.config/Typora/typora-user-images/image-20220513154122268.png)]
3.9.1 字符串测试

== 两边是否相等,相等时条件测试算成功

!= 两边是否不等,不相等时条件测试算成功

[root@node-0001 shell]# man bc
[root@node-0001 shell]# test a == a
[root@node-0001 shell]# echo $?
0
[root@node-0001 shell]# [ a != b ]
[root@node-0001 shell]# echo $?
0
[root@node-0001 shell]# b=
[root@node-0001 shell]# [ -z $b ]    # -z 判断变量是否为空 
[root@node-0001 shell]# echo $?
0
[root@node-0001 shell]# [  -z $b ]    # -z 判断变量是否为非空 
3.9.2 逻辑组合

条件 && 指令 条件成功才执行指令
条件 || 指令 条件失败才执行指令

当多个逻辑符号组合使用时
A && B && C A、B任务都成功才执行C

A && B || C A、B任务都成功不执行C

A || B && C A、B 任务有一个成功执行C

A || B || C A、B 任务有一个成功不执行C

3.10 变量初值

${变量名:-初值} 定义变量时如果为空,调用时会使用初值

#!/bin/bash
read -p "请输入用户名:"  u
[ -z $u ] && echo "必须输入用户名!"  && exit
useradd $u
read -p "请输入密码(默认123456):"  n
echo ${n:-123456} | passwd --stdin $u

4. 运算符

shell使用运算符,需要结合其他命令和工具来使用(因为shell中不支持简单的数学运算),如使用算符运算符就需要搭配的常用的工具有两种

  • awk
  • expr(使用频繁)

运算规则

  • 表达式和运算符之间必须要有空格,例如 3+2 是不对的,必须写成 3 + 2
  • 完整的表达式要被 两个``包含(在 Esc 键下边那个键)或者$(( ))

4.1 算数运算符

运算符说明举例
+加法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。

需要注意的点:

  • 在linux系统中乘号(*)前边必须加反斜杠才能实现乘法运算;

4.2关系运算符

​ shell中使用特殊的字符表示关系运算符,并且只支持数字不支持字符串,除非字符串是数字.

  • 运算符和数之间必须要用空格隔开
运算符说明举例a=10 b=20
-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。
# 编写脚本,每2分钟检查服务器的用户数量,如果发生变化
#!/bin/bash
x=$(cat /etc/passwd | wc -l)
[ $x -gt 52 ] && echo "system is changed" | mail -s "test" root  
[root@node-0001 shell]# crontab -e
*/2 * * * * /shell/user.sh

4.3 布尔运算符

运算符说明举例a=10 b=20
!非运算,表达式为 true 则返回 false,否则返回 true。[ ! false ] 返回 true。
-o或运算,有一个表达式为 true 则返回 true。[ $a -lt 20 -o $b -gt 100 ] 返回 true。
-a与运算,两个表达式都为 true 才返回 true。[ $a -lt 20 -a $b -gt 100 ] 返回 false。

4.4逻辑运算符

运算符说明举例 a=10 b=100
&&逻辑的 AND[[ $a -lt 100 && $b -gt 100 ]] 返回 false
||逻辑的 OR[[ $a -lt 100 || $b -gt 100 ]] 返回 true

4.5字符串运算符

运算符说明举例a=abc n=efg
=检测两个字符串是否相等,相等返回 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。

4.6 文件测试运算符

shell中的文件测试运算符用于检测在类unix系统中,文件的各种属性

操作符说明举例
-e file检测文件(包括目录)是否存在,如果是,则返回 true。[ -e $file ] 返回 true。
-b file检测文件是否是块设备文件,如果是,则返回 true。[ -b $file ] 返回 false。
-c file检测文件是否是字符设备文件,如果是,则返回 true。[ -c $file ] 返回 false。
-d file检测文件是否是目录,如果是,则返回 true。[ -d $file ] 返回 false。
-f file检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。[ -f $file ] 返回 true。
-g file检测文件是否设置了 SGID 位,如果是,则返回 true。[ -g $file ] 返回 false。
-k file检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。[ -k $file ] 返回 false。
-p file检测文件是否是有名管道,如果是,则返回 true。[ -p $file ] 返回 false。
-u file检测文件是否设置了 SUID 位,如果是,则返回 true。[ -u $file ] 返回 false。
-r file检测文件是否可读,如果是,则返回 true。 r权限对root无效[ -r $file ] 返回 true。
-w file检测文件是否可写,如果是,则返回 true。 w权限对root无效[ -w $file ] 返回 true。
-x file检测文件是否可执行,如果是,则返回 true。 x权限对root有效[ -x $file ] 返回 true。
-s file检测文件是否为空(文件大小是否大于0),不为空返回 true。[ -s $file ] 返回 true。
root@node-0001 shell]# ls -lh user.sh 
-rwxr-xr-x. 1 root root 126 57 14:34 user.sh
[root@node-0001 shell]# [ -d user.sh ] && echo "is"
not
[root@node-0001 shell]# [ -f user.sh ] && echo "is" || echo "not"
is
[root@node-0001 shell]# [ -r user.sh ] && echo "is" || echo "not"
is
[root@node-0001 shell]# [ -w user.sh ] && echo "is" || echo "not"
is
[root@node-0001 shell]# [ -x user.sh ] && echo "is" || echo "not"
is
[root@node-0001 shell]# [ -e user.sh ] && echo "is" || echo "not"
is

5. shell 编程流程控制语句

5.1 if 条件语句

If条件判断语句,通常以if开头,fi结尾。也可加入else或者elif进行多条件的判断

5.1.1 常用的单/双分支
# 单分支语句 ---比较大小
	if (条件表达式);then
		语句1
	fi
# 双分支if 语句
	if (表达式);then
		语句1
	else (表达式);then
		语句2
	fi
# 多支条件语句 ---判断成绩
	if (表达式);then
		语句1
	elif (表达式);then
		语句2
	elif (表达式);then
		语句2
	fi  
5.1.2 案例

使用单分支语句判断crond 进程是否在运行

#!/bin/bash
# this is check crond
# by author rivers on 2021-9.23

# 定义一个变量名
name=crond
num=$(ps -ef|grep $name|grep -vc grep)  #排除grep进程
if [ $num -eq 1 ];then
    echo "$num running!"
else
    echo "$num is not running!"
fi

判断主机是否连通

#!/bin/bash
ping -c 3 -i 0.2 -W 1 $1 &> /dev/null   //使用$1位置变量更方便 -c 次数 -i 间隔时间  -w 不通返回时间
if [ $? -eq 0 ];then
	echo "通了!"
else
	echo "不通!"
fi

判断系统目录是否存在

#!/bin/bash
# this is check directory 
 if  [  !  -d  /data/rivers  -a  !  -d  /tmp/rivers  ];then
 mkdir  -p  /data/rivers  
 fi

判断学生成绩等级

# if 语句可以直接对命令状态进行判断,就省去了获取$?这一步!
# 如果第一个条件符合就不再向下匹配
#!/bin/bash
# this check grade shell  
grade=$1
if [ $grade -gt 90 ];then
    echo "Is's very good!"
elif [ $grade -gt 70 ];then
    echo "Is's is good!" 
elif [ $grade -ge 60 ];then
    echo "pass" 
else
    echo "no pass"
fi

5.2 for循环

5.2.1 for 循环格式
#格式:for name [ [ in [ word ... ] ] ; ] do list ; done
  for 变量名 in 取值列表
  do
    语句 1
  done
  • in列表中可以包含替换、字符串和文件名等

  • in列表是可选的,如果默认不适用,将会循环使用命令行中的位置参数

    for i in “file1” “file2” “file3”
    for i in /boot/*
    for i in /etc/*.conf
    for i in $(seq -w 10) --》等宽的01-10
    for i in $(seq -w 10 100) --》等宽的10-100
    for i in {1…10}   1-10
    for i in $( ls )   当前目录
    for i in $(< file) 文件内容    #以空格隔断
    for i in “$@” --》取所有位置参数,可简写为for i
    

    取值列表使用变量会报错,可以使用eval

    #!/bin/bash
    read -p "input:" x
    s=0
    for i in `eval echo {1..$x}`
    do
    let s+=i
    done
    echo $s
    
5.2.2 案例

检查多台主机存活情况

#!/bin/bash
# check hosts is on/Off
Network=$1
for Host in $(seq 1 254)
do
ping -c 1 $Network.$Host > /dev/null && result=0 || result=1

if [ "$result" == 0 ];then
  echo -e "\033[32;1m$Network.$Host is up \033[0m"
  echo "$Network.$Host" >> /tmp/up.txt

else
  echo -e "\033[;31m$Network.$Host is down \033[0m"
  echo "$Network.$Host" >> /tmp/down.txt
fi
done

5.3 while 循环

5.3.1 格式

​ 主要用于对某个数据域进行循环读取、对文件进行遍历,通常用于需要循环某个文件或者列表,满足循环条件会一直循环,不满足则退出循环,其语法格式以while…do开头,done结尾与

​ while 关联的还有一个 until 语句,它与 while 不同之处在于,是当条件表达式为 false 时才循环.

while  (表达式)
do
  语句1
done

exit 可以终止循环,但脚本也终止
break 可以终止循环,继续循环后的任务
continue 可以终止当前循环,继续下一次循环

5.3.2 案例

continue与break 使用

#示例 1:在死循环中,满足条件终止循环
while true; do
  let N++
  if [ $N -eq 5 ]; then
    break
fi
  echo $N
done
输出: 1 2 3 4

#示例 2:举例子说明 continue 用法
N=0
while [ $N -lt 5 ]; do
  let N++
if [ $N -eq 3 ]; then
  continue
fi
  echo $N
done

输出: 1 2 4

# 打印 1-100 数字
i=0
while ((i<=100))
do
        echo  $i
        i=`expr $i + 1`
done

求1-100的总和

#!/bin/bash
# by author rivers on 2021-9-27
j=0
i=1
while ((i<=100))
do
     j=`expr $i + $j`
     ((i++))
done
echo $j

5.4 until循环

until循环和while循环相反,知道条件不成立时才进行循环。条件成立,立即终止循环。

格式:

until  条件    #条件不成立进入循环
do
	命令
done
#!/bin/bash
i=0
until ((i>100))
do
let sum+=$i
let i++
done
echo $sum

5.5 case 选择语句

Case选择语句,主要用于对多个选择条件进行匹配输出,与if elif语句结构类似,通常用于脚本传递输入参数,打印出输出结果及内容。语法格式如下:

case 模式名  in
  模式 1)
    命令;;
  模式 2)
    命令;;
*)
不符合以上模式执行的命令;;
esac

每个模式必须以右括号结束,命令结尾以双分号结束。

httpd 服务启动脚本

[root@web-server01~/script]# vim httpd_start.sh 
# check http server start|stop|starus
# by author rivers on 2021-9-27
while true
do
    echo -e "
    \033[31m start \033[0m
    \033[32m stop \033[0m 
    \033[33m status \033[0m
    \033[34m quit \033[0m 
"
read -p "请输入你的选择start|stop|quit:" char
case $char in
start)
    systemctl start httpd && echo "httpd服务已经开启" || echo "开启失败"
;;
stop)
    systemctl stop httpd && echo "httpd服务已经关闭" || echo "关闭失败"
;;
restart)
    systemctl restart httpd && echo "httpd服务已经重启" || echo "重启失败
"
;;
status)
    systemctl status httpd && echo -e "
        httpd 的服务状态 
;;
quit)

5.6 select选择语句

select 是一个类似于 for 循环的语句
Select语句一般用于选择,常用于选择菜单的创建,可以配合PS3来做打印菜单的输出信息,其语法格式以select…in do开头,done结尾:

select i in (表达式) 
do
语句
done

选择mysql 版本

#!/bin/sh
  
select ch in "begin" "end" "exit"
do
    case $ch in
    begin) echo "start something";;
    end)   echo "stop something";;
    exit)  exit;;
    *)  echo "error,input again";;
    esac
done        

打印lnmp选择菜单

#!/bin/bash
PS3="Please enter you select install menu:"
select i in http php mysql quit
do
case $i in
        http)
        echo -e "\033[31m Test Httpd \033[0m";;
        php)
        echo  -e "\033[32m Test PHP\033[0m";;
        mysql)
        echo -e "\033[33m Test MySQL.\033[0m";;
        quit)
        echo -e "\033[32m The System exit.\033[0m";exit
esac
done

6. shell 函数与数组

6.1 函数

6.1.1 函数定义

​ 将一组命令集或语句形成一个可用块,这些块称为函数。

​ Shell编程函数默认不能将参数传入()内部,Shell函数参数传递在调用函数名称传递,例如name args1 args2。

函数语法

[ function ] funname [()]
{
    action;
    [return int;]
}

参数说明:

  • function fun () 表示有返回参数的函数(如同C语言中的有返回类型的函数(int,char等))
  • fun() 表示无返回参数的函数(类似于C语言中的void类型函数)
  • 使用return可以返回参数值(一般为数值n),如果不使用,将默认以最后一条命令运行的结果作为返回值
  • return 后面的程序不再执行
  • 注意:函数的定义语句必须出现在调用之前,否则无法执行。

Shell 函数很简单,函数名后跟双括号,再跟双大括号,通过函数名直接调用,不加小括号。

#!/bin/bash
func() {
VAR=$((1+1))
return $VAR
echo "This is a function."
}
func
echo $?

所有的函数在使用前必须定义,这是因为shell解释器是顺序逐层执行的,当shell解释器发现定义的函数时,才会找到其对应的功能,进而执行。

6.1.2参数定义

​ 使用shell函数传递参数时,需要在函数体的内部,通过 $n 的形式来获取参数的值,与其他语言不同的是,这不是在定义函数的时候就给定参数,而是在函数体中获取到的参数,例如,$1表示第一个参数,$2表示第二个参数,参数调用列表如下

参数处理说明
$#传递到脚本或函数的参数个数
$*以一个单字符串显示所有向脚本传递的参数,空格隔开
$$脚本运行的当前进程ID号
$!后台运行的最后一个进程的ID号
$@与$*相同,但是使用时加引号,并在引号中返回每个参数
$-显示Shell使用的当前选项,与set命令功能相同。
$?显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
6.1.3 计算1到任意正整数的和
#!/bin/bash
sum()
{
        i=0
        s=0
        while ((i<$1+1))
        do
               let s+=i
               let i++
        done
echo "$s"
}
sum 100
sum 10

6.2数组

​ 数组是相同类型的元素按一定顺序排列的集合。在bash下,仅仅支持一维数组,并且没有限定数组的大小,不支持多维数组。类似于 C 语言,数组元素的下标由 0 开始编号(上述字符串也是这样)。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于 0。

6.2.1定义数组

在 Shell 中,用括号( )来定义表示数组,数组中元素用"空格"符号分割开。

格式:array=(元素 1 元素 2 元素 3 …)
用小括号初始化数组,元素之间用空格分隔。
定义方法 1:初始化数组 array=(a b c)
定义方法 2:新建数组并添加元素 array[下标]=元素
定义方法 3:将命令输出作为数组元素array=($(command))

array_name=(value1 value2 value3 value4)
array_test=(
value1 
value2 
value3 
value4
)
array_text[0]=value0
array=($(command))
6.2.2 数组操作

读取数组:和读取变量名相同,使用$符号,需要加上下标名

  valuen=${array_name[n]}
  echo ${array_name[@]} # 读取所有
  echo ${array_name[*]}	# 取所有

获取数组长度:获取数组长度的方法与获取字符串长度的方法相同

  # 取得数组元素的个数
  length=${#array_name[@]}	# 从头到尾取
  # 或者
  length=${#array_name[*]}	# 取所有
  # 取得数组单个元素的长度
  lengthn=${#array_name[n]}	# 取特定
6.2.3 遍历数组元素 — 案例
#方法 1:
#!/bin/bash
IP=(10.0.0.1 10.0.0.2 10.0.0.3)
for ((i=0;i<${#IP[*]};i++)); do
echo ${IP[$i]}
done
# bash test.sh
10.0.0.1
10.0.0.2
10.0.0.3

#方法 2:
#!/bin/bash
IP=(10.0.0.1 10.0.0.2 10.0.0.3)
for   IP   in ${IP[*]}; do
echo $IP
done 

7. shell字符串

7.1 字符串介绍

​ 在shell中字符串是shell编程中最常用最有用的数据类型,字符串可以用单引号,也可以用双引号,也可以不用引号。

# 使用单引号
str='this is a string'
# 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的
# 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。
#使用双引号
name="ohouhuoo"
str="please input your \"$name"\"
echo -e $str
# 可以在双引号中使用变量
# 可以在双引号中使用转义字符

7.2 字符串操作

1)计算字符串长度:在对变量进行取值时,使用" # "符号对字符串进行取值

${变量名称:截取位置:截取长度}

string="abcd"
echo ${#string}   # 统计字符串长度
# 编写脚本,给用户生成随机密码
#!/bin/bash
echo >./user.txt     #每次清空文本
str=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
for j in haha xixi lisi zhsan wangwu
do
pa=""
for i in {1..6}
do
        sp=${str:$RANDOM%62:1}
        pa=$sp$pa
done
echo "name:
passwd:$pa"&>>./user.txt
done

2)提取子字符串:使用字符串的截取命令,用于提取部分字符串。

索引从0开始,从第几个字符开始,取后面几个字符。

string="this is a test"
echo ${string:2:6} # 表示从第3个字符开始截取

3)替换字符串

格式: ${变量名/旧/新} 注意原始字符串并没有改变

a=1234
echo ${a/2/6}    //将1个字符2换成6
a=112233  
echo ${a/2/6}    //将1个字符2换成6
echo ${a//2/6}   //将所有字符2换成6
a=1122233
echo ${a/22/66}   //换2个
echo ${a/11/}    //将11替换成空,相当于删除

4)删除字符串

${变量名#要删除的内容} 掐头

${变量名%要删除的内容} 去尾 不能从中间开始

a=abcdef   //创建变量,作为素材
echo ${a#abc}    //掐头,从头删除abc
echo ${a##*c}  //从左往右删除到最后1个c
echo ${a%d*}    //去尾,从后删除def
echo ${a%%b*}  //从右往左删除到最后1个b
a=abcdefghijk   //创建变量,作为素材
echo ${a#*i}        //效果同上,精简写法,将i及其前面的全部删除
echo ${a%defghijk}  //去尾,删除到d
echo ${a%d*}      //效果同上,精简写法,将d以及后面的删除

5)查找字符串:用于查找字符的位置,输出结果为字符在字符串中所占的数据位置,如果查找多个字符,那哪个字母先出现就计算哪个,如下查找itit两个字符,t先出现,输出为1

string="this is a test"
echo `expr index "$string" it`  # 输出 1

8、 seq

seq 用于生成从一个数到另一个数之间的所有整数。

用法:seq [选项]… 尾数 默认1开始
 或:seq [选项]… 首数 尾数
 或:seq [选项]… 首数 增量 尾数

选项:

-f, --format=FORMAT 使用 printf 风格的浮点 FORMAT
-s, --separator=STRING 使用 STRING 分隔数字(默认值:\n)
-w, --equal-width 通过用前导零填充来均衡宽度
seq 5
seq 5 10
seq 2 2 10
seq -s : 2 2 10
seq -w 10
输出1-100中,不包含数字7,且不能被7整除的数
seq 100 | grep -v "7" | awk '$0%7!=0{print}'
seq -f 'dir%03g' 1 5|xargs mkdir

#seq -f “%3g” 13  数字位数为三位,不足补空格
  1
  2
  3
#seq -f “%03g” 1 5  数字位数为三位,不足补零
001
002
003
004
005
#seq -f "str%03g" 1 3
str001
str002
str003

可以用于在循环里生成要求的数。批量生成用户名或生成目录

seq -f 'tom%3g' 5
[root@develop shell]# a=tom
[root@develop shell]# seq -f '$a%g' 5
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值